MySQL - Почему COUNT с «больше чем» быстро, но «меньше чем» занимает вечность? - PullRequest
3 голосов
/ 20 августа 2010
SELECT count(*) c FROM full_view WHERE verified > ( DATE (NOW()) - INTERVAL 30 DAY)

Если я выполняю этот запрос, это занимает долю секунды, но если я переключаю оператор сравнения вокруг, это занимает эоны. Теперь первый способ count = 0 и второй способ count = 120000, но если я просто посчитаю всю таблицу, то это также займет микросекунды.

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

Это кажется бессмысленным: если он может быстро сосчитать все, что больше определенной даты, то почему нужно больше времени, чтобы сосчитать обратное? В любом случае он должен просматривать всю таблицу, верно? И все, что нужно для возврата, это число, поэтому пропускная способность не должна быть проблемой.

Объясните по запросу:

1, 'SIMPLE', 'b', 'range', 'updated,verified_index', 'updated', '3', '', 28, 'Using where'`    
1, 'SIMPLE', 'l', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'xyz_main.b.loc_id', 1, 'Using index'
1, 'SIMPLE', 'f', 'ALL', '', '', '', '', 2214, ''

EDIT:

Это может представлять интерес, я нашел эту информацию, когда запустил запрос:

Handler_read_rnd_next:

  • 254436689 (при выполнении меньше, чем)
  • 2 (больше чем)

Key_read_requests: 314393 против 33 (33 - наибольшее число для всех характеристик при использовании больше чем)

Handler_read_key: 104303 против 1

Обход представления и выполнение запроса непосредственно в основной таблице устраняет медлительность. Так что мне нужно сделать, чтобы ускорить его? Вид по сути такой:

SELECT x, y, z, verified FROM table1 LEFT JOIN table2 on tab2_ID = table2.ID LEFT JOIN table3 on tab3_ID = table3.ID

РЕШИТЬ: Фрэнки повел меня в правильном направлении. Вторая объединенная таблица (таблица компании) была объединена с помощью полнотекстового названия компаний. Я только недавно решил добавить целочисленный ключ к этой таблице. Столбец имени должен был быть проиндексирован, но я, возможно, испортил это. Во всяком случае я реорганизовал все. Я преобразовал внешний ключ в основной таблице, чтобы он соответствовал целочисленному идентификатору таблицы компаний, а не полному названию компании. Я переиндексировал эти столбцы в каждой таблице, а затем обновил представление, чтобы отразить новую точку соединения. Теперь он работает мгновенно в обоих направлениях. :) Так что я думаю, что целочисленные ключи были ключом. Проблема ушла, но все же я не чувствую, что мой первоначальный вопрос действительно был решен.

Спасибо за вашу помощь, ребята.

Ответы [ 4 ]

3 голосов
/ 20 августа 2010

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

EXPLAIN SELECT count(*) c 
FROM full_view 
WHERE verified > ( DATE (NOW()) - INTERVAL 30 DAY)

Давно забытое EXPLAIN почти всегда приносит что-то! ; )


Редактировать 1:
Это, вероятно, наступательная линия:

1, 'SIMPLE', 'f', 'ALL', '', '', '', '', 2214, ''

ALL указывает, что выполняется сканирование таблицы FULL.

Вы можете углубиться в синтаксис Explain на этой диаграмме .

Постарайся увидеть, в чем разница ...


Редактировать 2:
Этот документ, несомненно, прояснит ситуацию с выводом Explain. Пожалуйста, проверьте это.


Редактировать 3:
Пошаговый анализ команды объяснения.

1, 'SIMPLE', 'b', 'range', 'updated,verified_index', 'updated', '3', '', 28, 'Using where'`    
1 - id
SIMPLE - simple select, not using sub-queries
b - table name
range - only rows that are in a given range are retrieved, using an index
updated,verified_index - are both possible keys
updated - was the key eventually used
3 - key lenght
'' - this is the ref column and would show which columns or constants are compared to the index name in the key column to select rows from the table.
28 - number of rows mysql believes it must examine to execute the query
Using where - self explanatory
2 голосов
/ 20 августа 2010

Я предполагаю, что вычитание из Date(Now()) - это то, что занимает много времени для обработки. Для значений verified, которые уже меньше Date(Now()), оценка может быть закорочена, поскольку в этот момент она ДОЛЖНА быть ложной (при сравнении «больше чем»).

В ситуации, когда вы сравниваете с «меньше чем», время даты должно быть вычтено в каждом случае, независимо от текущего значения, так как у него нет никакого способа логически заключить выражение как истинное или ложное до оценки вычитание даты и времени

Впрочем, это только предположение - возьми это с крошкой соли.

1 голос
/ 20 августа 2010

Может случиться так, что есть статистика, сообщающая ядру базы данных, что нет записей для проверенных> 30 дней назад.В этом случае даже не нужно читать таблицу, а просто получать информацию из гистограммы статистики.

0 голосов
/ 20 августа 2010

Если у вас в таблице индекс verified, то более ограничительный COUNT (> один) будет быстрее. COUNT (*) без предложения WHERE может быстро вернуться, так как счетчик может быть получен из статистики таблицы / индекса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...