У меня есть этот запрос, который мне нужно выполнить, когда мне нужно проанализировать информацию о полях, сопоставляющую ее с другим полем в другой таблице, а затем ополоснуть и повторить несколько таблиц, в итоге это приведет к возврату требуемых строк.
Вопрос в том, как я могу ускорить это... он возвращает сотни тысяч строк, и он не слишком хорошо работает для моего клиента в разделе администратора, так как запрос вызывает сбой.
Вот запрос:
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM (
SELECT CU_id, CU_ship_name1, CU_ship_name2, CU_email
FROM customers
WHERE CU_solicit=1
AND CU_cdate >=".$startDate."
AND CU_cdate <=".$endDate."
)AS t1
INNER JOIN orders AS t2 ON t1.CU_id = t2.O_cid
INNER JOIN item AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN product AS t4 ON t3.I_pid = t4.P_id
INNER JOIN (
SELECT C_id FROM category WHERE C_store_type =1
) AS t5 ON t4.P_cat = t5.C_id
Таблицы "клиенты", "заказы", "элемент" обновляются каждый месяц десятками тысяч новых строк, а таблица "продукт" получает по меньшей мере сто новых строк каждый месяц.
Единственное, что я мог подумать, это создать новую таблицу, содержащую эту информацию (которая не является идеальным решением) и добавить индекс к этим таблицам. Я боюсь индекса, так как эти таблицы получают такое большое количество новых данных, но я готов попробовать его (всегда можно отменить его правильно?). Однако я не считаю, что индекс сам по себе исправит проблему.
UPDATE: теперь я использую этот запрос и получаю более быстрые результаты, индексирование всех строк WHERE и JOIN ON не помогло мне вообще... Я не могу понять, почему.
Удаление подзапросов:
оказал катастрофическое влияние на мою скорость запроса, а также с 3-4 секунд на запрос ниже до 151 с теми же параметрами.
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM customers AS t1
WHERE t1.CU_solicit=1
AND t1.CU_cdate>= 20100725000000
AND t1.CU_cdate<= 20100801000000
AND EXISTS(
SELECT NULL FROM orders AS t2
INNER JOIN item AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN product AS t4 ON t3.I_pid = t4.P_id
INNER JOIN (
SELECT C_id
FROM category
WHERE C_store_type = 2
) AS t5 ON t4.P_cat = t5.C_id
WHERE t1.CU_id = t2.O_cid);
Nevermind, я поменял их на обычные соединения и никаких подзапросов, и теперь эта вещь быстро осветляется после всего. Вот запрос:
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM customers AS t1
JOIN orders AS t2 ON t1.CU_id = t2.O_cid
JOIN item AS t3 ON t2.O_ref = t3.I_oref
JOIN product AS t4 ON t3.I_pid = t4.P_id
JOIN category AS t5 ON t4.P_cat = t5.C_id
WHERE t1.CU_solicit =1
AND t1.CU_cdate >=20100425000000
AND t1.CU_cdate <=20100801000000
AND t5.C_store_type =2
Я бы попробовал две вещи:
1) Добавьте индексы столбцов, которые вы используете в предложениях ON и WHERE
2) Исключите подзапросы, переписав их как обычные условия JOIN и WHERE
Только после того, как вы это сделали, и обнаружили, что у вас все еще проблема, если вы рассматриваете другие варианты.
Это действительно выглядит довольно простой запрос, за исключением ненужных подзапросов. Вы бы не ожидали, что он будет медленным даже с миллионами строк, если у вас нет указателей, у вас слишком мало памяти для MySQL, или вы очень плохо настроили сервер MySQL для доступных ресурсов.
Десять тысяч новых строк в месяц - ничто. Вы вводите новую строку каждые несколько минут. Это даже не соображение при определении того, какие индексы определять. MySQL на дешевом сервере может обрабатывать сотни вложений в секунду.
Я бы индексировал столбцы в ваших критериях так же, как и в ваших заявлениях ON. Индексы будут немедленно решать вашу проблему с сбоем и, вероятно, значительно не ухудшать ваши действия по изменению. Десятки тысяч строк каждый месяц на самом деле не так много строк - если ваша БД не находится на слабой машине.
Кроме того, я бы посмотрел на полное удаление подзапросов. Они часто замедляют производительность сервера sql. Вы также можете просмотреть перемещение запроса в хранимую процедуру, чтобы у сервера была возможность кэшировать его план выполнения.