2016-07-22 5 views
4

Я пытаюсь загрузить около 5 миллионов объектов, извлеченных из DB через спящий режим в хэш-карту. Я делаю это для двух типов классов (A & B). Я прохожу через поля. Ключ - поле из pojo, а значение - сами pojo.

1. Для класса A ключ является целым полем. Я могу загрузить карту менее чем за 20 секунд.

Для класса B
2.a) Тест 1, мой ключ является строковым полем. Когда я пытаюсь загрузить эти объекты в новый hashmap (новая попытка перезапуска java-процесса, так что никакого внимания с GC еще нет), для загрузки на карту 100K объектов требуется около 30 секунд.
2.b) Тест 2, когда я пытаюсь использовать другое поле этого класса (целочисленного типа) и загружать карту, он работает как 1-й и загружается менее чем за 20 секунд.
2.c) Тест 3, я задавался вопросом, была ли проблема типом данных. Итак, для класса B я попробовал другой подход к созданию строкового ключа с использованием целочисленного поля в # 2.b. (key = int_field + "") и загружается в < 20 секунд.Производительность Hashmap put зависит от ключей

Еще один тест, тест 4, который я сделал для класса типа B, - это способ, которым я создал ключ. Для 2.c я создал такой ключ
map.put (pojo.getIntField() + "", pojo);
Результат был, как упоминалось выше, в 2.c

2.d) Но когда я создал еще один поглотитель в POJO, что возвращаемый int_field + «» и использовал это в карте положить в
map.put (pojo.getIntFieldInStringForm(), pojo);
Производительность ухудшилась примерно до 30 секунд для объектов 100K.

Я знаю, что проблема связана с ключами, потому что я проверил фазу выборки db, добавив объекты результата в список и загрузив ее в < 20 секунд для обоих типов.

Я не могу понять причину этого. Если кто-то может пролить свет на это, это будет очень полезно. Очень признателен. Благодаря

Отредактировано: Добавление фрагменты кода здесь (простите форматирование/опечаток если таковые имеются):
Тест на # 1

Map<String, ClassA> map = new HashMap<String, ClassA>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassA> iterator = session.createQuery("from ClassA").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassA = iterator.next(); 
     map.put(objClassB.getIntField(), objClassA);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 


Тест на # 2.а

Map<String, ClassB> map = new HashMap<String, ClassB>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassB> iterator = session.createQuery("from ClassB").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassB = iterator.next(); 
     map.put(objClassB.getStringField(), objClassB);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 


Тест на # 2.b

Map<Integer, ClassB> map = new HashMap<Integer, ClassB>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassB> iterator = session.createQuery("from ClassB").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassB = iterator.next(); 
     map.put(objClassB.getIntField(), objClassB);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 


тест для # 2.c

Map<String, ClassB> map = new HashMap<String, ClassB>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassB> iterator = session.createQuery("from ClassB").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassB = iterator.next(); 
     map.put(objClassB.getIntField() + "", objClassB);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 


тест для # 2.d

Map<String, ClassB> map = new HashMap<String, ClassB>(); 
Session session = sessionFactory.openNewSession(); 
try { 
    Iterator<ClassB> iterator = session.createQuery("from ClassB").setFetchSize(1000).iterate(); 
    while (iterator.hasNext()) { 
     ClassB objClassB = iterator.next(); 
     map.put(objClassB.getIntFieldInStringForm() + "", objClassB);    
    } 
} 
catch (Exception e) { 
    e.printStackTrace(); 
} 
finally { 
    session.close(); 
} 
+0

Выполнение 'string + string' создает новый' StringBuilder', если он уже не обрабатывает операцию concat, так что это может повредить производительность, если вы делаете это совсем немного в цикле. Вместо этого используйте 'Integer.toString (int)'. Просто подсказка. Далее: насколько велики объекты 'String', которые вы загружаете из db? –

+0

Зачем вам делать '+" "' после 'getIntFieldInStringForm()', когда значение уже является строкой? --- Если производительность важна для вас, замените 'getIntField() +" "' на 'Integer.toString (getIntField())'. --- В 2a, насколько велики строки? – Andreas

+0

Мы не можем видеть, что вы делаете в своих тестовых корпусах. Создайте небольшой тестовый файл, который воспроизводит эту проблему. Или как в официальной закрытой причине: вопросы, требующие помощи по отладке («почему этот код не работает?») Должны включать в себя желаемое поведение, конкретную проблему или ошибку и кратчайший код, необходимый для воспроизведения в самом вопросе. Вопросы без четкого описания проблемы не полезны другим читателям. См.: Как создать минимальный, полный и проверенный пример. –

ответ

1

Чтобы поместить элементы в HashMap, то хэш-код из ключевых потребностей быть рассчитывается.Если в ваших строках 8 - 10 символов, есть некоторые расчеты, которые необходимо выполнить для сопоставления их с 32-битными хэш-кодами. Насколько велики ваши целые ключи? Если они меньше 100 000, для вычисления хэш-кода из 5 символов всего 5 символов, так что это немного быстрее.

У вас также есть удар производительности, когда два ключа вычисляют один и тот же хэш-код, который может произойти пару раз с вашими строковыми клавишами.

Когда вы используете уникальные целые числа в качестве ключей, хеш-столкновений никогда не произойдет. И, возможно, если вы используете строки, которые преобразуются целые числа, хэш-алгоритм String имеет меньшее количество коллизий.

+0

Мои целые ключи имеют длину 8 цифр. Кроме того, все еще запутывает разница в производительности, которую я вижу между 2.c и 2.d. Строковые ключи, которые я использую здесь, являются в основном числами в строчном формате. Поэтому я попытался преобразовать их в целое число и попробовал (около 8 цифр сейчас), и это также заняло около 30 секунд для 100K записей. – KNP

+0

Вы можете столкнуться с целыми ключами в зависимости от начальной емкости и коэффициента загрузки «HashMap». Поскольку @ nanda-kumar загружает 5M элементов на карту и не указывает начальную емкость, карта будет многократно перефразирована. – TreeRex

+0

Чтобы добавить еще один момент, когда мы говорим о коэффициенте нагрузки, я выполнил некоторые тесты, используя начальную емкость 5M и коэффициент загрузки или 1,0.Учитывая около 500 дубликатов ключей (а не хэш-код), я не видел большого улучшения производительности. Скорости снизились на несколько секунд меньше, чем 30 для 100K-записей, которые нигде не близки к числу, которое я вижу для теста №1. – KNP