#mysql
#mysql
Вопрос:
итак, у меня есть база данных объемом 560 МБ с самой большой таблицей 500 МБ (более 10 миллионов строк)
мой запрос должен объединять 5 таблиц и занимает около 10 секунд….
SELECT DISTINCT trips.tripid AS tripid,
stops.stopdescrption AS "perron",
Date_format(segments.segmentstart, "%H:%i") AS "time",
Date_format(trips.tripend, "%H:%i") AS "arrival",
Upper(routes.routepublicidentifier) AS "lijn",
plcend.placedescrption AS "destination"
FROM calendar
JOIN trips
ON calendar.vsid = trips.vsid
JOIN routes
ON routes.routeid = trips.routeid
JOIN places plcstart
ON plcstart.placeid = trips.placeidstart
JOIN places plcend
ON plcend.placeid = trips.placeidend
JOIN segments
ON segments.tripid = trips.tripid
JOIN stops
ON segments.stopid = stops.stopid
WHERE stops.stopid IN ( 43914, 23899, 23925, 23908,
23913, 19899, 23871, 43902,
23876, 25563, 18956, 19912,
23889, 23861, 23879, 23884,
23856, 19920, 19898, 23916,
23894, 20985, 23930, 20932,
20986, 22434, 20021, 19893,
19903, 19707, 19935 )
AND calendar.vscdate = Str_to_date('25-10-2011', "%e-%c-%Y")
AND segments.segmentstart >= Str_to_date('15:56', "%H:%i")
AND routes.routeservicetype = 0
AND segments.segmentstart > "00:00:00"
ORDER BY segments.segmentstart
что я могу сделать, чтобы ускорить это? любые советы приветствуются, я довольно новичок в sql…
но я не могу изменить структуру БД, потому что она не моя…
Комментарии:
1. Ваш запрос выглядит хорошо для меня. Если у вас есть индексы в столбцах stopid и segmentstart, они должны работать быстро.
2. Вы уже выполнили описание запроса? О чем это вам говорит? Какие индексы у вас есть? Какой движок базы данных вы используете?
3. @icarus Я поместил туда индексы, но это совсем не помогло: s
4. @rwilliams engine я innodb и я помещаю индексы в trips.vsid, calendar.vscdate, segments.segmentstart и routes.routeservicetype(спасибо Guffa), и это то, что говорит DESCRIBE, но я не знаю, что из этого сделать it…i.imgur.com/ZOm4p.jpg
5. Эта часть кажется нелогичной: И segments.segmentstart >= Str_to_date(’15:56′, «%H:%i») И segments.segmentstart> «00:00:00» Вы могли бы попытаться удалить ПОРЯДОК, возможно, это дало бы некоторые улучшения.
Ответ №1:
Используйте EXPLAIN, чтобы найти узкие места: http://dev.mysql.com/doc/refman/5.0/en/explain.html Тогда, возможно, добавьте индексы.
Если вам не нужно выбирать ВСЕ строки, используйте LIMIT, чтобы ограничить количество возвращаемых результатов.
Комментарии:
1. Я сделал описание и получил этот результат, но я действительно не знаю, что из этого сделать it…i.imgur.com/ZOm4p.jpg
2. У вас 12 миллионов строк в сегментах. Вам действительно нужно так много выбирать? Что вы делаете с результатом?
3. нет, этот запрос возвращает только 1000 строк, но количество строк варьируется в зависимости от даты, времени и этих идентификаторов остановки
Ответ №2:
Просто взглянув на запрос, я бы сказал, что вы должны убедиться, что у вас есть индексы на trips.vsid
, calendar.vscdate
, segments.segmentstart
и routes.routeservicetype
. Я предполагаю, что уже есть индексы для всех первичных ключей в таблицах.
Использование explain
, как предложил Бриедис, покажет вам, насколько хорошо работают индексы.
Возможно, вы захотите добавить покрывающие индексы для некоторых таблиц, например, индекс trips.vsid
where tripid
и routeid
включены. Таким образом, база данных может использовать только индекс для данных, которые необходимы из таблицы, а не для чтения из фактической таблицы.
Редактировать:
План выполнения сообщает вам, что он успешно использует индексы для всего, кроме segments
таблицы, где он выполняет сканирование таблицы и фильтрует по where
условию. Вы должны попытаться создать покрывающий индекс для segments.segmentstart
, включив tripid
и stopid
.
Комментарии:
1. добавление индексов в segments.segmentstart фактически замедлило его: s
2. @mars: Это может произойти, если у вас уже есть аналогичный индекс, который может использовать база данных, и она считает, что недавно добавленный индекс выглядит лучше, но на самом деле хуже.
3. @mars как теперь выглядит вывод EXPLAIN?
4. @mars: я добавил предложение выше на основе плана выполнения.
Ответ №3:
Попробуйте добавить индекс кластеров в routes
таблицу для обоих routeservicetype
и routeid
.
В зависимости от частоты данных в routeservicetype
поле, вы можете получить улучшение, сократив объем данных, сравниваемых в соединении с таблицей trips.
Глядя на план объяснения, вы также можете захотеть изменить последовательность использования таблицы, используя STRAIGHT_JOIN
вместо JOIN
(или INNER JOIN
) , поскольку у меня были реальные улучшения с помощью этой техники.
По сути, поместите таблицу с наименьшим количеством строк извлеченных данных в начале запроса и таблицу с наибольшим количеством строк в конце (в данном случае, возможно segments
, таблицу?), За исключением простых поисковых запросов (например. для описания).
Вы также можете рассмотреть возможность изменения WHERE
предложения для фильтрации segments
таблицы stopid
вместо stops
таблицы и создания кластеризованного индекса в segments
таблице на ( stopid
, tripid
и segmentstart
) — этот индекс будет эффективно удовлетворять двум предложениям join и двум where из одного индекса…
Для построения индекса…
ALTER TABLE segments ADD INDEX idx_qry_helper ( stopid, tripid, segmentstart );
И измененное WHERE
предложение…
WHERE segments.stopid IN ( 43914, 23899, 23925, 23908,
23913, 19899, 23871, 43902,
23876, 25563, 18956, 19912,
23889, 23861, 23879, 23884,
23856, 19920, 19898, 23916,
23894, 20985, 23930, 20932,
20986, 22434, 20021, 19893,
19903, 19707, 19935 )
:
:
В конце концов, 10-секундный ответ на то, что кажется сложным запросом к довольно большому набору данных, не так уж и плох!