SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 13.04.2011 12:48:29

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Вопрос про ORDER BY и буфер сортировки

Допустим, есть запрос вида SELECT ... ORDER BY col LIMIT N

1. Если col в индексе, то, вроде как, filesort не используется и буфер сортировки не используется.
Как в этом случае действует MySQL? Достанет N первых записей по ключу и сразу же их отдаст?

2. Если col в индексе, но запрос вида ORDER BY col, col2, то индекс использоваться уже не будет, а будет использоваться filesort, верно?

Например, есть таблица со 100 записями, из которых 20 записей с col = 'A' и 25 записей с col = 'B'. В запросе указано LIMIT 30, 10 (т.е. записи с 30-й по 39-ю).
Как я понимаю, теоретически у MySQL есть два пути для дальнейших действий:

а) MySQL вытащит все 100 записей в sort_buffer и начнет там сортировать. Отсортировав все 100 записей, выберет записи с 30 по 39 и отдаст клиенту.

б) MySQL возьмет первые 20 записей в sort_buffer — где col = 'A'. Увидит, что 20 < 30 (т.е. нужные записи еще не начались), пойдет за записями со следующим по сортировке значением col. Возьмёт 25 записей (col = 'B') и поместит их в sort_buffer. Увидит, что 25 + 20 > 39, т.е. записей уже хватает, поэтому прекратит брать записи из таблицы и начнет сортировать то, что уже набралось в sort_buffer.

Вот и вопрос: каким образом будет действовать MySQL.

Если первым, то это немного страшно, и вот почему: допустим, есть таблица с простыми индексами на колонках. Запросы вида ORDER BY col выполняются с использованием индексов. Однако если в сортировку прибавить col2, то получается, индекс по col использоваться не будет (что неочевидно, т.к. колонка следует первой и проиндексирована — привычно ожидать использования индекса).
А если запрос без WHERE, то сортироваться будет вообще все записи! (ведь на стадии занесения в sort_buffer записи никак не фильтруются)
Получается, что sort_buffer_size должен быть размеров порядка таблицы (точнее, порядка тех колонок таблицы, которые участвуют в запросе, кроме TEXT и BLOB).

Неактивен

 

#2 13.04.2011 14:52:17

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

Re: Вопрос про ORDER BY и буфер сортировки

Пропущена важная деталь - есть ли WHERE. Если WHERE нет, и есть индекс на col, то в случае ORDER BY col будет выбирать по ключу, а в случае ORDER BY col, col2 тоже используется ключ col, а при равных значениях будет сортировать через буфер. В последней ситуации поможет индекс (col, col2). Если есть условие WHERE, то выборка будет чаще всего начинаться с WHERE, в таком случае индекс будет использоваться, если он продолжает условие (если условие точное - без > < и OR). Подробно алгоритм доступа по ключу описан в курсе оптимизации MySQL, посмотри там.

Неактивен

 

#3 13.04.2011 15:53:26

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: Вопрос про ORDER BY и буфер сортировки

rgbeast написал:

в случае ORDER BY col, col2 тоже используется ключ col

В том-то и дело, что нет: при добавлении в сортировку второй колонки запрос перестаёт использовать индекс!

Код:

mysql> SHOW CREATE TABLE goods\G
*************************** 1. row ***************************
       Table: goods
Create Table: CREATE TABLE `goods` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `type_id` smallint(6) NOT NULL,
  ...
  PRIMARY KEY (`id`),
  ...
  ) ENGINE=MyISAM 
1 row in set (0.00 sec)


mysql> EXPLAIN SELECT id, type_id FROM goods ORDER BY id LIMIT 10\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: goods
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 10
        Extra:
1 row in set (0.00 sec)


mysql> EXPLAIN SELECT id, type_id FROM goods ORDER BY id, type_id LIMIT 10\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: goods
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 364
        Extra: Using filesort
1 row in set (0.00 sec)

Неактивен

 

#4 15.04.2011 20:55:34

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Вопрос про ORDER BY и буфер сортировки

Да, перестает, а что тебя смущает? Любая сортировка без индекса плоха.

Неактивен

 

#5 15.04.2011 21:07:57

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: Вопрос про ORDER BY и буфер сортировки

Меня смущает, что не используется левая часть индекса (хотя могла бы: если надо 10 записей из 1000 и известно, что первые 5 записей имеют одно значение колонки col1, а вторые 7 записей имеют другое, то незачем лезть за следующими, поскольку при сортировки они все равно будут отброшены).

Но главным образом смущает это потому, что это очень коварно: есть привычка составлять запросы, исходя из того, что будет использоваться хотя бы левая их часть. Например, WHERE a = ... and b IN (...) ORDER BY c будет использовать индекс (a,b). А ORDER BY a, b, c — не будет.

Неактивен

 

#6 16.04.2011 01:22:08

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Вопрос про ORDER BY и буфер сортировки

Ну нет. Представь себе, что у тебя a выбирает два блока по 1000 строк. Будет ли
эффективнее пересортировывать внутри блока или целиком? А где тогда находится
критерий, когда сортировать по твоему эффективнее внутри блока, а когда цели-
ком?

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

Неактивен

 

#7 16.04.2011 15:03:28

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: Вопрос про ORDER BY и буфер сортировки

Представь себе, что у тебя a выбирает два блока по 1000 строк. Будет ли
эффективнее пересортировывать внутри блока или целиком?

Так я же не предлагаю пересортировывать внутри блока. Я
предлагаю лишь выбрать эти блоки по a. Ведь легче выбрать два
блока по 1000 строк и потом их все вместе отсортировать, чем сортировать прямо сразу, но при этом читать миллион. (Или нет?)

Неактивен

 

#8 16.04.2011 21:59:44

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Вопрос про ORDER BY и буфер сортировки

Ээ... а какой смысл выбирать их по а, если потом надо будет выбрать все остальные
строки (WHERE же ты не написал?), отсортировать их тоже вместе с общим набором?

Неактивен

 

#9 17.04.2011 02:12:42

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: Вопрос про ORDER BY и буфер сортировки

какой смысл выбирать их по а, если потом надо будет выбрать все остальные
строки

Вот именно, что не надо!
Попробую еще раз, попонятней.
Есть 1000 строк.
Запрос ORDER BY A, B LIMIT 10
При этом есть ключ по A.
Смотрим в ключ. Видим первые 5 строк. У них значение A одно и то же, следовательно как они там точно отсортированы будут — мы не знаем. Но они точно будут идти первыми (хотя и непонятно, как они будут внутри себя отсортированы по B, это и не важно), поэтому мы их забираем.
Смотрим дальше. Видим еще, например, 7 строк. У них всех тоже одно и то же значение A. И эти 7 строк будут явно идти после предыдущих 5 (поскольку первичная сортировка по A), но точно перед какими-либо еще из оставшихся в таблице. Т.к. нам надо 10 строк, а у нас есть только 5 — забираем эти 7 (придется забрать все 7, т.к. про col2 внутри них мы ничего не знаем).
Теперь у нас есть 12 строк. 12 > 10, поэтому больше нам строк не надо. Теперь мы идем за col2 для этих 12 строк (а не для всех 1000) и сортируем 12 строк окончательно.

MySQL же просто читает все 1000 строк, сортирует их все и только потом делает вывод о том, какие строки отдать. Да, 1000 — последовательное чтение вместо выдергиваний по индексу. Но сортировать-то надо будет всю тысячу (а если миллион? каково процессору будет?)

Неактивен

 

#10 18.04.2011 16:38:56

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Вопрос про ORDER BY и буфер сортировки

Теперь у нас есть 12 строк. 12 > 10, поэтому больше нам строк не надо.

Надо. Дальше у нас еще есть три миллиона строк с одинаковой col1, а потом одна
строка с тем же col1, но самым маленьким col2.

Неактивен

 

#11 19.04.2011 18:45:58

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: Вопрос про ORDER BY и буфер сортировки

Надо.

Не понимаю, зачем?
Мы выбрали все строки с двумя значениями col1, которые являются экстремальными (т.е. самыми большими или самыми маленькими из всех имеющихся; у нас в ключе отсортировано, и мы это знаем наверняка).
Это значит, что другие строки ни при каких условиях вперед этих в результат запроса не залезут.
При этом имеющихся строк нам уже хватает.
Зачем нам вообще остальные записи тогда трогать?

Неактивен

 

#12 20.04.2011 21:23:50

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Вопрос про ORDER BY и буфер сортировки

Хорошо. Отсортируй данные
(1,1),(1,2),(1,3),(1,4), .... (1,0),(1,1000)
используя свой алгоритм (стоит ORDER BY first,second LIMIT 3).

Неактивен

 

#13 21.04.2011 09:20:21

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 849

Re: Вопрос про ORDER BY и буфер сортировки

Как я понимаю, ты, в целом, хотел сказать следующее: "существуют случаи, когда сортировка в индексе не позволяет узнать достаточно о порядке следовании записей, и все равно быстрее сразу читать таблицу".

Согласен с этим.
Но!
Когда запрос WHERE a BETWEEN ..., такие случаи тоже существуют.
На то у оптимизатора есть варианты: если по ключу отбираются пятьсот тысяч записей из миллиона, то быстрее сканировать таблицу, если же из миллиона отбираются десять записей - вытаскивать по ключу. Это в случае WHERE.
В случае ORDER BY принцип такой: если по ключу сортируются и отбираются пятьсот тысяч записей из миллиона (и остальные пятьсот тысяч не нужны), а нужно десять - сканировать таблицу, если по ключу сортируются и отбираются десять записей из миллиона, и нужно десять - все равно сканировать таблицу.

Не понимаю, почему в случае WHERE по двум колонкам, где одна не в индексе, можно им пользоваться, а в случае ORDER BY — нет.

Неактивен

 

#14 21.04.2011 16:32:32

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Вопрос про ORDER BY и буфер сортировки

Вернемся к нашему примеру. Тебе надо отобрать 10 строк, в которых
первое значение до 10, а второе значение — тоже до 10. Правда же,
в этом случае будет работать ровно твой алгоритм?

В одном случае тебе надо найти произвольные 10 строк, удовлетворя
ющие критерию, а во втором — тебе надо найти 10 лучших из всех.
И между all и any (не смотря на один квантор) есть огромная разница.

Неактивен

 

#15 30.04.2011 10:47:57

relax
Участник
Зарегистрирован: 01.11.2010
Сообщений: 19

Re: Вопрос про ORDER BY и буфер сортировки

Можно я влезу в ваш разговор?
SELECT SQL_NO_CACHE * FROM `temp` WHERE `a` IN (3,4)  ORDER BY `sort` DESC LIMIT 10
Регулярное мучение мое, т.к. все время filesort
1 миллион записей, на которые делаются filesort. Против того, что алгоритм не умеет обходить N деревьев-это жестоко.
Вот SELECT SQL_NO_CACHE * FROM `temp` WHERE (`a`=3) ORDER BY `sort` DESC LIMIT 10
Находится вход, получается поддерево. Все ок, все быстро.
SELECT SQL_NO_CACHE * FROM `temp` WHERE `a` IN (3,4)  ORDER BY `sort` DESC LIMIT 10
Находится два входа, получаются два поддерева, ставим курсоры в две вершины поддерева и спускаемся. добавляется 10 сравнений, все.
10 дополнительных операций сравнения против filesort для 1 млн.

Отредактированно relax (30.04.2011 10:48:59)

Неактивен

 

#16 30.04.2011 15:36:27

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Вопрос про ORDER BY и буфер сортировки

Да, но MySQL не может использовать более одного индекса при поиске
по таблице (даже если это два экземпляра одного и того же индекса).

Ну и для того, чтобы Ваша задачка отработала быстро, нужно всего лишь
добавить второй экземпляр таблицы smile Т.е.
SELECT .. FROM (
  SELECT .. WHERE a = 3 ORDER BY sort DESC LIMIT 10
  UNION
  SELECT .. WHERE a = 4 ORDER BY sort DESC LIMIT 10
) t ORDER BY sort DESC LIMIT 10.

Неактивен

 

#17 30.04.2011 15:45:36

relax
Участник
Зарегистрирован: 01.11.2010
Сообщений: 19

Re: Вопрос про ORDER BY и буфер сортировки

индекс то один -составной (`a`,`sort`). и он вполне подходил, если бы руки у них дошли  сделать как надо.
И больше одного индекса может использоваться- вспомните merge
а решение я знаю. Что не отменяет того факта, что это-знатный изврат.
кстати, писать надо UNION ALL а то лишняя операция проверки уникальности.

Неактивен

 

#18 30.04.2011 17:56:56

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Вопрос про ORDER BY и буфер сортировки

У меня есть радикальное предожение — напишите патч и отправьте его в upstream?
Ну правда, если это так легко делается wink

В реальном мире приходится считаться с реальными ограничениями. Использование
одного индекса — это реальное ограничение. INDEX_MERGE — это костыль, который
сделали такие же люди, как Вы, — которые поняли, что в некоторых местах можно
использовать несколько индексов понятным образом. Сделайте тоже хорошо?

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson