Оптимизация запросов с использованием WHERE IN - PullRequest
0 голосов
/ 04 июня 2010

Мне интересно, может ли кто-нибудь объяснить, как рассчитывается IN? Ну, в конце концов я пытаюсь выяснить, почему этот запрос медленный и как его оптимизировать. Я ждал более 3 минут, и когда я отменил запрос, он возвратил только 1000 строк, что, похоже, не займет столько времени.

SELECT t2.* 
FROM report_tables.roc_test_results as t2 
WHERE t2.job IN (SELECT DISTINCT(t1.job) 
                   FROM report_tables.roc_test_results as t1 
                  WHERE t1.operation = 'TEST' 
                    AND result = 'Passed' 
                    AND STR_TO_DATE(t1.date_created,'%d-%M-%Y') BETWEEN '2009-10-01' 
                                                                    AND '2009-10-31')

Я не уверен, что должен возвращать общий запрос; если бы мне пришлось угадывать, что я сказал бы около 2000 записей, подзапрос возвращает 332 (336, когда не определен).

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

По запросу, результаты для DESC ... (кстати, пожалуйста, не смейтесь, я самоучка, поэтому я уверен, что эта таблица ужасно спроектирована.)

Field                     Type               Null     Key    Default    Extra
------                      -----              -----     ---    -------    -----
operation                 varchar(10)         NO   
tester                 varchar(25)            NO   
result                 varchar(45)            NO   
fail_mode              varchar(45)         NO   
primary_failure        varchar(25)           NO   
ref_des                varchar(45)           NO   
rf_hours               varchar(15)          NO   
ac_hours               varchar(15)          NO   
comments               text              NO   
job                    varchar(15)           NO   
rma                    bigint(20) unsigned    NO   
item                   varchar(45)          NO   
item_description       text                  NO   
serial                 varchar(25)            NO   
created_by             varchar(25)            NO   
collection             bigint(20) unsigned    NO    PRI  
date_created           varchar(15)          NO   

Ответы [ 3 ]

1 голос
/ 04 июня 2010

Тип данных date_created должен измениться на DATETIME, прежде чем стоит определять индекс для столбца. Причина в том, что индекс будет бесполезен, если вы меняете тип данных со строки на DATETIME, как в настоящее время.

Вы упомянули, что используете LOAD DATA INFILE, и что исходный файл содержит даты в формате DD-MON-YY. MySQL будет неявно преобразовывать строки в DATETIME, если используется формат YY-MM-DD , поэтому, если вы можете исправить это в исходном файле перед использованием LOAD DATA INFILE, остальные должны быть на месте.

После этого индекс покрытия с использованием:

  • работа
  • работа
  • результат
  • date_created

... было бы неплохо.

0 голосов
/ 04 июня 2010

Мой совет - заменить IN на JOIN, а затем рассмотреть возможность добавления индексов для некоторых ваших столбцов, таких как задание, и, возможно, операция и / или результат. Вы должны прочитать об индексах в руководстве MySQL, а также об использовании EXPLAIN для оптимизации ваших запросов:

http://dev.mysql.com/doc/refman/5.1/en/indexes.html

http://dev.mysql.com/doc/refman/5.1/en/using-explain.html

Вот пример преобразования IN в JOIN:

SELECT distinct t2.* 
FROM roc_test_results as t2
inner join roc_test_results as t1 on t1.job = t2.job
WHERE t1.operation = 'TEST' 
AND t1.result = 'Passed' 
AND STR_TO_DATE(t1.date_created,'%d-%M-%Y') BETWEEN '2009-10-01' AND '2009-10-31';
0 голосов
/ 04 июня 2010

Прежде всего вам не нужно отличительное в подзапросе, так как IN все равно удаляет дубликаты Вам нужен вызов функции в предложении WHERE, и есть ли у вас индекс для столбца date_created?

что происходит, когда вы меняете

WHERE STR_TO_DATE(t1.date_created,'%d-%M-%Y') 
BETWEEN '2009-10-01' AND '2009-10-31')

до

WHERE 1.date_created >= '2009-10-01' 
AND 1.date_created < '2010-01-01'

Иногда индексы не будут использоваться, если вы используете функции для столбца

...