Я попал в узкое место производительности БД, где сейчас? - PullRequest
8 голосов
/ 28 июля 2011

У меня есть несколько запросов, которые занимают слишком много времени (300 мс) сейчас, когда база данных выросла до нескольких миллионов записей. К счастью для меня, запросы не должны просматривать большую часть этих данных, этих последних 100 000 записей будет достаточно, поэтому я планирую сохранить отдельную таблицу с самыми последними 100 000 записей и выполнить запросы в соответствии с этим. Если у кого-то есть какие-либо предложения для лучшего способа сделать это, это было бы здорово. Мой реальный вопрос: каковы варианты, если запросы должны были работать с историческими данными, каков следующий шаг? Вещи, о которых я думал:

  • Обновление оборудования
  • Использовать базу данных в памяти
  • Кэширование объектов вручную в вашей собственной структуре данных

Правильны ли эти вещи и есть ли другие варианты? Есть ли у некоторых поставщиков БД больше функциональности, чем у других, чтобы справиться с этими проблемами, например указание конкретной таблицы / индекса, который будет полностью в памяти?

Извините, я должен был упомянуть об этом, я использую mysql.

Я забыл упомянуть об индексации выше. До сих пор индексирование было моим единственным источником улучшений, чтобы быть честным. Чтобы выявить узкие места, я использовал maatkit для запросов, чтобы показать, используются ли индексы.

Я понимаю, что теперь ухожу от того, для чего был задан вопрос, поэтому, возможно, мне стоит сделать еще один. Моя проблема в том, что EXPLAIN говорит, что запрос занимает 10 мс, а не 300 мс, о которых сообщает jprofiler. Если у кого-то есть какие-либо предложения, я буду очень признателен. Запрос:

select bv.* 
from BerthVisit bv 
inner join BerthVisitChainLinks on bv.berthVisitID = BerthVisitChainLinks.berthVisitID 
inner join BerthVisitChain on BerthVisitChainLinks.berthVisitChainID = BerthVisitChain.berthVisitChainID 
inner join BerthJourneyChains on BerthVisitChain.berthVisitChainID = BerthJourneyChains.berthVisitChainID 
inner join BerthJourney on BerthJourneyChains.berthJourneyID = BerthJourney.berthJourneyID 
inner join TDObjectBerthJourneyMap on BerthJourney.berthJourneyID = TDObjectBerthJourneyMap.berthJourneyID 
inner join TDObject on TDObjectBerthJourneyMap.tdObjectID = TDObject.tdObjectID 
where 
BerthJourney.journeyType='A' and 
bv.berthID=251860 and 
TDObject.headcode='2L32' and 
bv.depTime is null and 
bv.arrTime > '2011-07-28 16:00:00'

и вывод из EXPLAIN:

+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+-------------------------------------------------------+
| id | select_type | table                   | type        | possible_keys                               | key                     | key_len | ref                                            | rows | Extra                                                 |
+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+-------------------------------------------------------+
|  1 | SIMPLE      | bv                      | index_merge | PRIMARY,idx_berthID,idx_arrTime,idx_depTime | idx_berthID,idx_depTime | 9,9     | NULL                                           |  117 | Using intersect(idx_berthID,idx_depTime); Using where | 
|  1 | SIMPLE      | BerthVisitChainLinks    | ref         | idx_berthVisitChainID,idx_berthVisitID      | idx_berthVisitID        | 8       | Network.bv.berthVisitID                        |    1 | Using where                                           | 
|  1 | SIMPLE      | BerthVisitChain         | eq_ref      | PRIMARY                                     | PRIMARY                 | 8       | Network.BerthVisitChainLinks.berthVisitChainID |    1 | Using where; Using index                              | 
|  1 | SIMPLE      | BerthJourneyChains      | ref         | idx_berthJourneyID,idx_berthVisitChainID    | idx_berthVisitChainID   | 8       | Network.BerthVisitChain.berthVisitChainID      |    1 | Using where                                           | 
|  1 | SIMPLE      | BerthJourney            | eq_ref      | PRIMARY,idx_journeyType                     | PRIMARY                 | 8       | Network.BerthJourneyChains.berthJourneyID      |    1 | Using where                                           | 
|  1 | SIMPLE      | TDObjectBerthJourneyMap | ref         | idx_tdObjectID,idx_berthJourneyID           | idx_berthJourneyID      | 8       | Network.BerthJourney.berthJourneyID            |    1 | Using where                                           | 
|  1 | SIMPLE      | TDObject                | eq_ref      | PRIMARY,idx_headcode                        | PRIMARY                 | 8       | Network.TDObjectBerthJourneyMap.tdObjectID     |    1 | Using where                                           | 
+----+-------------+-------------------------+-------------+---------------------------------------------+-------------------------+---------+------------------------------------------------+------+---------------------------------------

7 rows in set (0.01 sec)

Ответы [ 7 ]

3 голосов
/ 28 июля 2011
  1. Убедитесь, что все ваши индексы оптимизированы.Используйте explain в запросе, чтобы увидеть, эффективно ли он использует ваши индексы.
  2. Если вы делаете тяжелые соединения, тогда подумайте о том, чтобы выполнить этот расчет в Java.
  3. Подумайте об использовании других БД, таких как NoSQL.Возможно, вы сможете выполнить некоторую предварительную обработку и поместить данные в Memcache, чтобы вам немного помочь.
1 голос
/ 28 июля 2011

Вместо того, чтобы создавать отдельную таблицу для последних результатов, подумайте о секционировании таблиц.MySQL имеет эту функцию, встроенную начиная с версии 5.1


Просто чтобы прояснить: я не говорю, что это решение ваших проблем.Только одна вещь, которую вы можете попробовать

1 голос
/ 28 июля 2011

Считать, что изменение дизайна, как это, не является хорошим знаком - держу пари, что у вас все еще есть достаточная производительность, чтобы выжать с помощью EXPLAIN, настройки переменных db и улучшения индексов и запросов. Но вы, вероятно, прошли тот момент, когда «пробовать вещи» работает очень хорошо. Это возможность научиться интерпретировать анализы и журналы и использовать то, что вы изучаете, для конкретных улучшений индексов и запросов.

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

Какую самую смешную пессимизацию вы видели?

1 голос
/ 28 июля 2011

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

а) Конфигурация mysql и убедитесь, что она максимально использует аппаратное обеспечение

б) посмотрите на оборудование. Вы не говорите, какое оборудование вы используете. Вы можете обнаружить, что репликация является опцией в вашем случае, если вы можете купить два или три сервера, чтобы разделить операции чтения из базы данных (записи должны выполняться на центральный сервер, но операции чтения могут быть прочитаны любым числом ведомых устройств). .

0 голосов
/ 28 июля 2011

Я понимаю, что теперь ухожу от того, для чего предназначался вопрос так что, возможно, я должен сделать еще один. Моя проблема в том, что EXPLAIN говорит запрос занимает 10 мс, а не 300 мс, о которых сообщает jprofiler.

Тогда ваша проблема (и решение) должны быть в Java, верно?

0 голосов
/ 28 июля 2011

Поиск в последних 100 000 записей должен быть очень быстрым, у вас определенно есть проблемы с индексами. Используйте EXPLAIN и исправьте это.

0 голосов
/ 28 июля 2011

Я бы начал с попытки оптимизировать таблицы / индексы / запросы, прежде чем предпринимать какие-либо из перечисленных вами мер. Вы копались в плохо выполняющихся запросах до такой степени, что вы абсолютно уверены, что достигли предела возможностей вашей СУБД?

Редактировать: если вы действительно оптимизированы должным образом, но у вас все еще есть проблемы, подумайте о создании Материализованного представления для точных данных, которые вам нужны. Это может быть, а может и не быть хорошей идеей, основанной на большем количестве факторов, чем вы предоставили, но я бы поставил ее в верхней части списка вещей для рассмотрения.

...