Как оптимизировать запросы MySQL с помощью констант? - PullRequest
1 голос
/ 23 ноября 2008

ПРИМЕЧАНИЕ. Оригинальный вопрос спорный, но отсканируйте его до конца.

У меня есть запрос, который я хочу оптимизировать, который выглядит примерно так:

select cols from tbl where col = "some run time value" limit 1;

Я хочу знать, какие ключи используются, но независимо от того, что я передаю для объяснения, он может оптимизировать предложение where («Невозможно, ГДЕ заметил ...»), потому что я дал ему константу.

  • Есть ли способ заставить mysql не выполнять постоянную оптимизацию в объяснении?
  • Я что-то упустил?
  • Есть ли лучший способ получить нужную мне информацию?

Редактировать: EXPLAIN, кажется, дает мне план запроса, который будет результатом постоянных значений. Поскольку запрос является частью хранимой процедуры (и планы запросов IIRC в spocs генерируются до их вызова), это не приносит мне пользы, поскольку значение не является постоянным. Я хочу выяснить, какой план запроса сгенерирует оптимизатор, когда он не знает, каково будет действительное значение.

Я что-то упустил?

Edit2: в других местах кажется, что MySQL всегда генерирует планы запросов, если вы не стараетесь использовать их повторно. Даже в хранимых процедурах. Отсюда может показаться, что мой вопрос спорный.

Однако это не делает то, что я действительно хотел знать, спорным: Как оптимизировать запрос, который содержит значения, которые являются постоянными в любом конкретном запросе, но где я, программист, не могу Заранее неизвестно, какое значение будет использоваться? - Например, скажем, мой клиентский код генерирует запрос с номером в предложении where. Иногда число приводит к невозможности , в то время как условие , а иногда - нет. Как я могу использовать объяснение, чтобы проверить, насколько хорошо оптимизирован запрос?

Лучший подход, который я вижу сразу, - запустить EXPLAIN на нем для полной матрицы существующих / несуществующих случаев. На самом деле это не очень хорошее решение, так как это было бы сложно и подвержено ошибкам вручную.

Ответы [ 3 ]

5 голосов
/ 23 ноября 2008

Вы получаете «Невозможно ГДЕ заметили», потому что указанное вами значение находится не в столбце, а не только потому, что оно является константой. Вы можете либо 1) использовать значение, которое существует в столбце, либо 2) просто сказать col = col:

explain select cols from tbl where col = col;
4 голосов
/ 05 мая 2009

Например, скажем, мой код на стороне клиента генерирует запрос с номером в предложении where.

Иногда число приводит к невозможному предложению where, в противном случае оно не будет.

Как использовать объяснение, чтобы проверить, насколько хорошо оптимизирован запрос?

MySQL создает разные планы запросов для разных значений связанных параметров.

В этой статье вы можете прочитать список того, когда оптимизатор MySQL делает что:

    Action                                      When

    Query parse                                 PREPARE
    Negation elimination                        PREPARE
    Subquery re-writes                          PREPARE

    Nested JOIN simplification                  First EXECUTE
    OUTER->INNER JOIN conversions               First EXECUTE

    Partition pruning                           Every EXECUTE
    COUNT/MIN/MAX elimination                   Every EXECUTE
    Constant subexpression removal              Every EXECUTE
    Equality propagation                        Every EXECUTE
    Constant table detection                    Every EXECUTE
    ref access analysis                         Every EXECUTE
    range/index_merge analysis and optimization Every EXECUTE
    Join optimization                           Every EXECUTE

В этом списке отсутствует еще одна вещь.

MySQL может перестраивать план запроса на каждую JOIN итерацию : такой называется range checking for each record.

Если у вас есть составной индекс для таблицы:

CREATE INDEX ix_table2_col1_col2 ON table2 (col1, col2)

и такой запрос:

SELECT  *
FROM    table1 t1
JOIN    table2 t2
ON      t2.col1 = t1.value1
        AND t2.col2 BETWEEN t1.value2_lowerbound AND t2.value2_upperbound

, MySQL НЕ будет использовать индекс RANGE доступ от (t1.value1, t1.value2_lowerbound) до (t1.value1, t1.value2_upperbound). Вместо этого он будет использовать индекс REF access для (t1.value) и просто отфильтровывает неправильные значения.

Но если переписать запрос так:

SELECT  *
FROM    table1 t1
JOIN    table2 t2
ON      t2.col1 <= t1.value1
        AND t2.col1 >= t2.value1
        AND t2.col2 BETWEEN t1.value2_lowerbound AND t2.value2_upperbound

, затем MySQL перепроверит индекс RANGE access для каждой записи из table1 и решит, использовать ли RANGE доступ на лету.

Вы можете прочитать об этом в этих статьях в моем блоге:

Все эти вещи используют RANGE CHECKING FOR EACH RECORD

Возвращаясь к вашему вопросу: нет никакого способа определить, какой план будет MySQL использовать для каждой данной константы, поскольку нет плана до того, как константа будет задана.

К сожалению, нет способа заставить MySQL использовать один план запроса для каждого значения связанного параметра.

Вы можете контролировать порядок JOIN и INDEX, выбранные с помощью предложений STRAIGHT_JOIN и FORCE INDEX, но они не будут принудительно определять определенный путь доступа к индексу или запрещать IMPOSSIBLE WHERE.

С другой стороны, для всех JOIN, MySQL использует только NESTED LOOPS. Это означает, что если вы построите правильный JOIN порядок или выберете правильные индексы, MySQL, вероятно, выиграет от всех IMPOSSIBLE WHERE.

0 голосов
/ 05 марта 2009

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

Используя индексы для определенных столбцов (или даже для комбинации столбцов, если вы всегда запрашиваете данные столбцы вместе). Если у вас есть индексы, их может использовать планировщик запросов.

Относительно «невозможных» значений: планировщик запросов может сделать вывод, что данное значение отсутствует в таблице из нескольких источников:

  • если в конкретном столбце есть индекс, он может заметить, что конкретное значение больше или меньше любого значения в индексе (минимальные / максимальные значения требуют постоянного времени для извлечения из индексов)
  • если вы передаете неправильный тип (если вы просите, чтобы числовой столбец был равен тексту)

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

...