Индексация MySQL для нескольких запросов (*) - PullRequest
1 голос
/ 14 декабря 2010

Я потерян в отношении индексации. У меня есть довольно сложное веб-приложение, которое я создаю для клиента, и оно имеет несколько запросов count (*), которые все выполняются очень медленно (0,3 секунды)

Вот краткий пример

SELECT COUNT( * ) AS  `count` 
FROM  `vehicles` 
WHERE  `VehicleLocation_province` =  'Alberta'
AND  `default_image_URI` IS NOT NULL 
AND  `default_image_URI` !=  ''

Вот объяснение ..

 1 SIMPLE vehicles ref VehicleLocation_province,VehicleLocation_province_...     VehicleLocation_province 2 const 14128 Using where

Я даже не могу заставить этот запрос использовать правильный индекс, не говоря уже о некоторых более сложных запросах, таких как

SELECT * , ( 6371 * ACOS( COS( RADIANS( 53.543564 ) ) * COS( RADIANS( lat ) ) * COS( RADIANS( lng ) - RADIANS( - 113.490456 ) ) + SIN( RADIANS( 53.543564 ) ) * SIN( RADIANS( lat ) ) ) ) AS  `distance` 
FROM  `vehicles` 
WHERE  `Make` =  'Pontiac'
AND  `BodyStyle` =  'Sedan'
AND  `VehiclePrice` >=  '1'
AND  `VehiclePrice` <=  '36000'
AND  `VehiclePrice` IS NOT NULL 
AND  `default_image_URI` IS NOT NULL 
AND  `default_image_URI` !=  ''
HAVING `distance` < 50
ORDER BY `VehicleReceivedDate` DESC LIMIT 25

Объяснять

1 SIMPLE vehicles ref Make,BodyStyle,VehicleLocation_province_2 Make 99 const 5821 Using where; Using filesort

Я знаю, что мне нужно избегать временных таблиц и сортировок файлов, где это возможно ... но как это практически достигается, когда несколько из этих запросов count (*) должны выполняться при каждом запросе с изменением группирования и порядка параметров?

Ответы [ 2 ]

2 голосов
/ 14 декабря 2010

Что ж, единственный способ ускорить выполнение запросов к индексам - это обеспечить, чтобы индексы покрывали достаточно условий, чтобы селективность стала полезной (или чтобы СУБД могла использовать индексы для вычисления агрегатов, таких как count).

Не забывайте, что наличие индекса на (Make) и индекса на (BodyStyle) равно , а не то же самое, что индекс на (Make, BodyStyle).

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

Вы можете проверить это, создав индекс (VehicleLocation_province, default_image_URI), а затем запустив запрос и / или изучив объяснение.

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

Несколько замечаний здесь:

  • обратите внимание на ваши условия IS NOT NULL и !='' - если эти условия обычно присутствуют в ваших запросах, это говорит о том, что ваш дизайн не соответствует требованиям, и что вы денормализовали разные сущности в одну таблицу, так что теперь вам нужно их отсортировать каждый раз, когда вы хотите использовать данные (это всего лишь указание, и я предполагаю, что вы применяете эти условия много , что может не соответствовать действительности)
  • сказав, что, если вы посмотрите на 2-й запрос и если Make и BodyStyle покрыты составным индексом и имеют низкую селективность, запрос все равно будет выполняться быстро
  • mysql должен выбрать один индекс для доступа к данным, и он попытается выбрать индекс, который возвращает наименьшее количество строк с учетом статистики и доступных условий (так что дальнейшие условия должны пройти через наименьшее количество записей) - если этот индекс помогает только с уменьшением результирующего набора, сортировка будет выполняться с использованием файловой сортировки. Чтобы индекс был полезен как для выбора строк, так и для сортировки, он должен иметь полезный порядок или индексированные столбцы, например, в приведенном выше индексе запроса для (Make, BodyStyle, VehicleReceivedDate) может быть уловка
  • Добавление правильных индексов в таблицу должно помочь, но индексы не могут исправить проблемы с дизайном
0 голосов
/ 29 января 2011

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

Sphinx может даже @geodist для расчета радиуса с SetGeoAnchor ( $attrlat, $attrlong, $lat, $long )

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

Хотелось бы подуматьсервера поиска ранее в проекте - теперь, немного поздно, чтобы избавиться от проблем с производительностью.

http://sphinxsearch.com

...