SQL WHERE IN (ID1, ID2, ID3) против WHERE UNIQUE_ID = IDX - PullRequest
0 голосов
/ 15 января 2019

Я создал таблицу с некоторыми фиктивными данными. Таблица ( ARTICLES ) состоит из id, author_id, заголовка, описания, а таблица ( AUTHOR ) состоит из author_id, name, article_list.

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

Первый

SELECT * FROM  articles WHERE  author_id = 100;

и, во-вторых, если я сохраню весь список всех статей в форме списка внутри моей таблицы авторов, тогда я смогу использовать

SELECT * 
  FROM  articles 
 WHERE id IN (100, 1100, 2100, 3100, 4100, 5100, 6100, 
            7100, 8100, 9100, 10100, 11100, 12100, 13100, 
            14100, 15100, 16100, 17100, 18100, 19100, 20100,
            21100, 22100, 23100, 24100, 25100, 26100, 27100,
            28100, 29100, 30100, 31100, 32100, 33100, 34100);

Первый запрос занял 0,0329 с, а второй - 0,0017 с.

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

Все, что я знаю, второй запрос будет выполняться как

SELECT * 
  FROM articles 
 WHERE id = 100 
    OR id = 1100 
    OR id = 2100... and so on

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Кэширование.

Если вы запускаете сервер, а затем запускаете запрос, в buffer_pool (или кеше таблицы или ...) еще ничего нет. Таким образом, нужно открыть несколько файлов и прочитать несколько блоков. 32,9 мсек могут указывать на то, что вам нужно ударить диск (если жесткий диск) 3 раза со скоростью примерно 10 мс каждый.

Если вы выполните идентичный запрос второй раз, все будет кэшировано, и это займет всего несколько миллисекунд, обычно менее 10 мс.

Так как первый запрос заполнил кеш каким-то материалом, второй запрос обнаружил большинство, а может быть, и все блоки, в которых он нуждался. Таким образом, это был, вероятно, только процессор, без ввода-вывода 1,7 мс разумно.

Возможная проблема ... У вас включен "Query cache"? Если это так, то (в определенных ситуациях) последующее выполнение любого SELECT найдет набор результатов в КК и вернет очень быстро, возможно, <1 мс. Один из способов избежать QC (для реалистичной синхронизации) - сделать <code>SELECT SQL_NO_CACHE ....

Представленный вами запрос OR оптимизирован для представленного вами IN. То есть они заканчивают тем, что были идентичны. (Использование OR с разными столбцами снижает производительность; здесь дело обстоит не так.)

Сроки подсказок:

  • Используйте SELECT SQL_NO_CACHE ... (чтобы избежать контроля качества)
  • Выполните запрос дважды и используйте время second . (Это позволяет избежать других проблем с кэшированием.)

Теперь проанализируем, что произойдет, если у нет есть индекс для author_id.

  • Оба запроса будут сканировать всю таблицу.
  • Очевидно, это сравнительно небольшая таблица, поскольку вы можете прочитать все это за 32,9 мс.
  • Разница между 32,9 и 1,7 только кэшируется. (У меня есть Правило большого пальца, которое говорит, что соотношение между ними равно 10. Для этого показателя 32,9 / 1,7 достаточно близко к моему RoT, чтобы поддержать его.)

Если бы у вас было INDEX(author_id), оба запроса могли бы выполняться быстрее, кешироваться или нет.

0 голосов
/ 15 января 2019

Это может быть потому, что могут быть тысячи author_ids и для:

 SELECT * FROM  articles WHERE  author_id = 100;

Каждая строка должна быть пройдена, потому что она применяется ко всем строкам столбца

А для:

 SELECT * FROM  articles WHERE id IN (100, 1100, 2100, 3100, 4100, 5100, 6100, 7100, 8100, 9100, 10100, 11100, 12100, 13100, 14100, 15100, 16100, 17100, 18100, 19100, 20100, 21100, 22100, 23100, 24100, 25100, 26100, 27100, 28100, 29100, 30100, 31100, 32100, 33100, 34100);

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

...