2010-10-21 5 views
13

Вот моя проблема, я выбираю и делаю несколько объединений для получения правильных элементов ... он тянет в большом количестве строк, превышающих 100 000. Этот запрос занимает более 5 минут, если для диапазона дат установлено значение 1 год.Как я могу ускорить запрос MySQL с несколькими объединениями

Я не знаю, возможно ли это, но я боюсь, что пользователь может расширить диапазон дат до десяти лет и свернуть его.

Кто-нибудь знает, как я могу ускорить это? Вот запрос.

SELECT DISTINCT t1.first_name, t1.last_name, t1.email 
FROM table1 AS t1 
INNER JOIN table2 AS t2 ON t1.CU_id = t2.O_cid 
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref 
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id 
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id 
WHERE t1.subscribe =1 
AND t1.Cdate >= $startDate 
AND t1.Cdate <= $endDate 
AND t5.store =2 

Я не самый большой с mysql, поэтому любая помощь будет оценена!

Заранее благодарен!

UPDATE

Вот это объяснить вы просили

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE t5 ref  PRIMARY,C_store_type,C_id,C_store_type_2 C_store_type_2 1 const 101  Using temporary 
1 SIMPLE t4 ref  PRIMARY,P_cat P_cat 5 alphacom.t5.C_id 326  Using where 
1 SIMPLE t3 ref  I_pid,I_oref I_pid 4 alphacom.t4.P_id 31 
1 SIMPLE t2 eq_ref O_ref,O_cid  O_ref 28 alphacom.t3.I_oref 1  
1 SIMPLE t1 eq_ref PRIMARY  PRIMARY  4 alphacom.t2.O_cid 1 Using where 

Также я добавил индекс table5 строк и table4 строк, потому что они на самом деле не изменится, однако другие таблицы обойти 500-1000 записей в месяц ... Я слышал, вы должны добавить индекс в таблицу, в которой есть много новых записей .... это правда?

+3

Это поможет узнать таблицы и индексирование на месте - пожалуйста, обновите, чтобы включить инструкции CREATE TABLE. Необходимость 'DISTINCT' заставляет меня задаться вопросом, за какую таблицу (-ы) отвечает за это. –

+0

Помощник EXPLAIN тоже поможет. – ceejayoz

+0

-OMG Ponies, я не знаю, что вы подразумеваете под операциями create table. -Ceejayoz, я добавил EXPLAIN – BinarySolo00100

ответ

10

Я хотел бы попробовать следующее:

Во-первых, убедитесь, есть указатели на следующие таблицы и столбцы (каждый набор столбцов в круглых скобках должен быть отдельный индекс):

table1 : (subscribe, CDate) 
     (CU_id) 
table2 : (O_cid) 
     (O_ref) 
table3 : (I_oref) 
     (I_pid) 
table4 : (P_id) 
     (P_cat) 
table5 : (C_id, store) 

Во-вторых, если добавив вышеуказанные показатели не улучшить положение вещей столько, сколько вы хотите, попробуйте переписать запрос на качестве

SELECT DISTINCT t1.first_name, t1.last_name, t1.email FROM 
    (SELECT CU_id, t1.first_name, t1.last_name, t1.email 
    FROM table1 
    WHERE subscribe = 1 AND 
      CDate >= $startDate AND 
      CDate <= $endDate) AS t1 
    INNER JOIN table2 AS t2 
    ON t1.CU_id = t2.O_cid 
    INNER JOIN table3 AS t3 
    ON t2.O_ref = t3.I_oref 
    INNER JOIN table4 AS t4 
    ON t3.I_pid = t4.P_id 
    INNER JOIN (SELECT C_id FROM table5 WHERE store = 2) AS t5 
    ON t4.P_cat = t5.C_id 

Я надеюсь, что здесь, что первый суб -select значительно сократит количество строк, которые будут рассматриваться для присоединения, надеюсь, что последующие объединения будут меньше работать. То же самое можно сказать по поводу второго подвыбора на таблице5.

В любом случае, беспорядок с ним. Я имею в виду, в конечном счете, это просто ВЫБОР - вы не можете ничего на нее нанести. Изучите планы, которые генерируются каждой другой перестановкой, и попытайтесь выяснить, что хорошо или плохо для каждого.

Делитесь и наслаждайтесь.

+0

Спасибо, я думаю, это поможет, я буду возиться. Я не очень разбираюсь в MySQL или базе данных вообще, поэтому я очень ценю вашу помощь. Кроме того, я обновил вопрос, я не добавлял индекс в некоторые из таблиц, потому что я не был уверен, должен ли я, так как каждый месяц добавляется около 500-1000 новых строк. – BinarySolo00100

+1

Я закончил с этим, и это сделало огромный ОГРОМНЫЙ удар, спасибо! – BinarySolo00100

+1

@ BinarySolo00100 - рад слышать, что это помогло. Что касается добавления индексов - я предполагаю, что вы обеспокоены тем, что накладные расходы индексирования могут замедлять вставки и обновления. Мой опыт в том, что по какой-то причине люди (особенно DBA) слишком беспокоятся об индексировании накладных расходов и в конечном итоге с плохой производительностью SELECT из-за этого. Я считаю, что это случай преждевременной оптимизации, т. Е. Беспокоиться о несуществующей потенциальной проблеме. Пока у вас нет заметной проблемы, у вас нет проблем. Добавьте индексы (или что-то еще) и MEASURE, MEASURE, MEASURE - затем действуйте на эту информацию. –

8

Удостоверьтесь, что ваши столбцы даты и все столбцы, на которые вы соединяетесь, индексируются.

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

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

-1

Похоже, вы должны подумать о доставке подмножеств (подкачки) или ограничить результаты каким-либо другим способом, если нет причин, по которым пользователям нужна каждая строка, возможно, сразу. Как правило, 100K строк больше, чем средний человек может переварить.

+1

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

+0

Я не совсем уверен, почему я был заблокирован, когда я ясно сказал «если нет причин, по которым пользователям нужна каждая строка, возможно, сразу». –

3

Ну, во-первых, сделать подзапрос проредить table1 вниз только записи вы на самом деле хотите, чтобы пойти на все проблемы присоединения ...

SELECT DISTINCT t1.first_name, t1.last_name, t1.email 
FROM ( 
SELECT first_name, last_name, email, CU_id FROM table1 WHERE 
table1.subscribe = 1 
AND table1.Cdate >= $startDate 
AND table1.Cdate <= $endDate 
) AS t1 
INNER JOIN table2 AS t2 ON t1.CU_id = t2.O_cid 
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref 
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id 
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id 
WHERE t5.store = 2 

Затем начните смотреть на изменение направленности стыки ,

Кроме того, если t5.store только очень редко 2, то переверните эту идею вокруг: постройте подзапрос t5, затем присоедините его назад и назад и назад.

1

Попробуйте добавить указатели на поля, к которым вы присоединяетесь. Это может или не может улучшить производительность.

Кроме того, это зависит от используемого вами двигателя. Если вы используете InnoDB, проверьте свои параметры конфигурации. Я столкнулся с аналогичной проблемой, поскольку стандартная конфигурация innodb не будет масштабироваться так же, как конфигурация по умолчанию myisam.

1

Как все говорят, убедитесь, что у вас есть индексы.

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

Без EXPLAIN работать не так много.Также имейте в виду, что MySQL будет смотреть ваш JOIN и выполнять все возможные решения перед выполнением запроса, что может занять некоторое время. Когда у вас будет оптимальный порядок JOIN от EXPLAIN, вы можете попробовать и принудительно выполнить этот заказ в своем запросе, исключив этот шаг от оптимизатора.

2

В настоящее время ваш запрос возвращает все соответствующие строки в таблице2-table5, чтобы установить, является ли t5.store = 2. Если какой-либо из table2-table5 имеет значительно больший ряд строк, чем таблица1, это может значительно увеличить количество обработанных строк - следовательно, следующий запрос может выполнить значительно лучше:

SELECT DISTINCT t1.first_name, t1.last_name, t1.email 
FROM table1 AS t1 
WHERE t1.subscribe =1 
AND t1.Cdate >= $startDate 
AND t1.Cdate <= $endDate 
AND EXISTS 
(SELECT NULL FROM table2 AS t2 
INNER JOIN table3 AS t3 ON t2.O_ref = t3.I_oref 
INNER JOIN table4 AS t4 ON t3.I_pid = t4.P_id 
INNER JOIN table5 AS t5 ON t4.P_cat = t5.C_id AND t5.store =2 
WHERE t1.CU_id = t2.O_cid); 
Смежные вопросы