Как стать автором
Обновить

Комментарии 57

срочно харбакат…
Чуть чуть опередили!
Сделайте хабракат пожалуйста, очень неудобно!
Значительно эффективнее было бы писать об этом в личные сообщения. Это если Вы, конечно, хотели именно чтобы я вспомнил о нём, а не чтоб написать об этом в комментариях…
а что делать, если в InnoBD у меня foreign keys и на поля, которые связываются я ставлю индексы? здесь же общий индекс делать бессмыслено?
Всегда интуитивно делал комбинированные индексы, а сейчас получил доказательства своей правоты. Спасибо за статью. :)
Спасибо за статью, давно хотел разобраться но руки не доходили.

Хорошо, а как со скоростью апдейта комбинированного/двух индексов? Насколько скорость обновления индекса по двум полям отличается от индекса по одному полю?
+время удаления и вставки
Это всё фигня. Составные индексы, конечно, хорошо, но в случае B-Tree надо учитывать, что поиск по индексу может использовать только начальное подмножество от порядке индексируемых полей. Т.е., если есть составной индекс по полям (a, b, c, d), то такой индекс ускорит поиск по любой из следующих групп полей: (a), (a, b), (a, b, c), (a, b, c, d). Но не ускорит, например, поиск по (b, c, d). А поиск по (a, c, d) будет производиться с той же скоростью (тем же количеством итерированных элементов), как и поиск по (a).

А вот в PostgreSQL есть GIST и GIN-индексы. С помощью хитрых contrib-модулей (впрочем, идущих в комплекте с PostgreSQL), с их помощью пожно создать составной индекс по нескольким полям, так, что любая выборка любых полей из проиндексированных будет находиться по индексу. Т.е., создав индекс по (a, b, c, d, e), можно будет выполнить запрос SELECT * FROM table WHERE a = 5 AND c = 7 AND e = 8, и (если планировщик посчитает, что надо использовать индекс) все результирующие записи можно будет получить по индексу.
Имеет ли значение, в каком порядке идут проиндексированные поля в выражении where? Или mysql самостоятельно оптимизирует поиск?

порядок выражений в условии влияния не оказывает, для оптимизатора есть другие приоритеты, например, первоначальное значение имеют константы.
НЛО прилетело и опубликовало эту надпись здесь
зачем ты зашел в этот блог, myserg?
НЛО прилетело и опубликовало эту надпись здесь
А ты тупенький наивно думаешь что все вот так все бросили и на постгре кинулись пересаживаться на тебя насмотревшись?

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

PS
Ничего против разработчиков постгре не имею. Свою работу они делают очень хорошо. Но вот комьюнити у них… Пусть ему спасибо скажут за то, что они сливали, сливают и будут сливать MySQL.
НЛО прилетело и опубликовало эту надпись здесь
А вам не кажется, что MySQL и PostgreSQL предназначены всё-таки для разных целей? Вам же не приходит в голову поставить Oracle, пусть даже OracleXE на сайт с посещаемостью в 100 человек в сутки? Так для чего тогда разводить холивары по поводу мускула и постреса? Постгрес является безусловно самой мощной из бесплатных СУБД, но его сложность не даст ему получить такую широкую популярность, как была у mSQL и как есть сейчас у MySQL.
НЛО прилетело и опубликовало эту надпись здесь
Во-первых, Oracle XE является бесплатной версией Oracle. Во-вторых, сложность СУБД оценивается далеко не возможностью выбрать движок. В-третьих, адекватнее надо быть, а то людям может показаться, что Ваша карма является реальным отражением Вашей ущербности.
НЛО прилетело и опубликовало эту надпись здесь
Плюсовая карма в профиле как минимум не говорит ни о чём ;) А вот Ваша ущербность и одноклеточность сквозит во всём. Учи матчасть, тролль ;)
Вообще, постгрес умеет совмещать результаты скана b-tree индексов в памяти (aka Bitmap index scan + Bitmap AND/OR)
Кстати о multicolumn GiST/GIN индексах — штука весьма экзотическая, в интернетах каких-либо тестов производительности найти не выходит. Есть мнение, что в случае выборки по нескольким полям такое сочетание выиграет лишь в исключительных случаях у bitmap-combine скана или обычного скана одного индекса с фильтрами по остальным полям.
Ждем on-disk bitmap индексы, заготавливаем OLAP кубья :)
Есть, есть тесты.

Тьфу. Слишком рано отправилось. www.scribd.com/doc/4846380/-GIN-GiST-PostgreSQL — даже на русском :) У GIST insert-ы этак раз в 10 быстрее select-ов, у GIN — ровно наоборот.
Вот только давайте без холиваров.

То что MySQL использует только первый столбец это понятно, было бы иначе и вопрос бы не стоял — делали бы один индекс по всем полям под все запросы (в общем случае) и все.
Я не в рамках холивара, а для сравнения B-Tree и GIST/GIN индексов. Если в MySQL появятся/существуют оные, я только за.

А что, MySQL использует именно только первый столбец? Я думал, B-Tree в общем случае подразумевает возможность использования любой последовательности столбцов с начала (как я и упомянул).
Да, пардон, не верно выразился.
Раз тут знающие люди собрались, можно вопрос задать?

Все банально: есть таблица, в ней есть FK на другую таблицу, нужно получить связанные значения. Насколько запрос вида `id in (18,20,30)` хуже джоина, и хуже ли он? Предположим, что id нужных связанных объектов уже известны, например, получены другим запросом. Понятно, что 2 запроса хуже, чем один, но тот первый запрос не учитываем, считаем, что id'шники известны нам и так, волшебным образом.
Если ID известны, то лучше без джоина — в слуае джоина он выберет данные из второй таблички а потом сделает тот же «id in (18,20,30)»
Запросы JOIN'ами, как правило, тяжело воспринимаются оптимизаторами БД, и MySQL — совсем не исключение :). Объясняется это тем, что ему приходится просматривать много возможных комбинаций индексов, которые ему предстоит использовать (ведь и таблиц же несколько...). Поэтому, в зависимости от количества записей и расстановки индексов, это может быть как быстрее, так и медленней. Если Вы работаете с огромными массивами данных, я бы предпочёл не испытывать судьбу и обойтись простыми запросами, пусть и бОльшим их количеством.

Я слышал, что в SpyLog так вообще использование JOIN запрещено :).
Т.е. если (допустим) из огромной базы постов надо выбрать 1 пост, а потом комменты к нему из 2-й таблицы — выбголнее делать 2 простых запроса, чем один с джойном и WHERE post_id = N? Не бред ли? Неужели JOIN так неоптимален?
Если пост один, а комментов много, то да, ИМХО, лучше 2 запроса. Почему бред-то? JOIN — одна из самых труднооптимизируемых операций во всех СУБД. И чем больше записей, тем хуже.

В общем, чего мне Вам рассказывать — попробуйте сами :). Может, на Вашем наборе данных всё будет наоборот. Тут не угадаешь…
А как вы собрались сделать один запрос? Получив ряды состоящие из идентичной части полей поста и меняющейся части комментариев? Ну т.е.

PostID | PostText | CommentID | CommentText

И так все строки, сколько есть комментариев? Конечно так будет намного медленнее.
Ну смотрите, мне казалось:

1) одним запросом — MySQL выбирает данные поста, затем из второй таблицы комменты к нему (допустим ищет по индексу), и возвращает все это. С друго стороны, если MySQL сначала составит огромную объединенную таблицу «все посты— все комменты», то это конечно лежать будет ((

2) 2 запроса — всяко займут времени больше чем один, т.к. накладные расходы на передачу/обработку запроса/анализ и прочее в 2 раза больше :)

Ну ок. если что потом сгенерирую пару огромных таблиц и проверю, я чувствую тут по другому не проверить.
Накладные расходы занимают куда меньше времени, чем возврат присоединённого к каждой строке текста сообщения. Поэтому решение в таких случаев вполне естественное: сначала извлечь данные о посте, затем данные о комментариях.
Ну вот, а я уже начал придумывать хитрый модуль для работы с таблицами и автоматической генерацией джойнов, а оказалось все намного проще!
А как на счет варианта с подзапросом в IN()?

SELECT c.* FROM comments c WHERE c.id IN ( SELECT comments_id FROM blabla WHERE blabla.id = 1)
?
Создаётся временная таблица… Не думаю, что это сильно лучше.
Если количество результатов разумное и влезает в HEAP (размер которого задаётся в настройках MySQL), то вариант не так уж и плох.
Ну-ну.

Погуглите про подзапросы в MySQL.

Потом на реальных данных верещать начинают, почему у меня запрос 5 мин. выполняется?!!!

Он же такой быстрый был. И эксплайн такой красивый :-(

Про коммент ниже. С константами там действительно все Ок.
т.е. подзапрос получается менее выгоден, чем джойн и два отдельных запроса?
Не все и не всегда однозначно.

Нужно просто понимать как работают подзапросы в MySQL.
Проблема в том, что оптимизатор в очень многих случаях считает " c.id IN " неконстантным значением и выполняет подзапрос не один, а столько раз, сколько посчитает нужным. Причем эксплайн напишет — все замечательно, индексы правильные и все тип-топ. Вот только не видно сколько раз будет выполнен подзапрос.
На тестах, когда данных немного и нет реальных нагрузок — это незаметно, но на продакшнах проблемы могут повылазить и не по детски.

В общем случае лучше уходить к джойну. Хотя он тот еще не сахар.

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

Ну а дальше все просто. Я это для себя так решил
sql.ru/forum/actualthread.aspx?tid=650047&hl=%ec%e5%f1%fc%e5

Заворачиваю в ХП.
Выполняю подзапрос, его результат через GROUP_CONCAT в переменную, что-то типа
SELECT GROUP_CONCAT(fld) FROM table INTO myvar;

Собираю строку запроса
@query = CONCAT('SELECT fld1 FROM table1 WHERE fld2 IN (', myvar, ')';

Препарирую @query и выполняю его.
В IN константа, и оптимизатор не дуркует.

Грабли там только одни, счас не помню, но по моему при NULL или пустой строке в конкатенируемом поле, результат GROUP_CONCAT может выглядеть типа ",,,77,2". Ну и соответственно ошибка при выполнении.
Да, сейчас «трендово» брать списки у Sphinx'а, а потом делать выборку WHERE… IN :)
Также обратите внимание на то, что выполнение запроса заняло в 5 раз больше времени несмотря на то, что FULL SCAN прошёл примерно в 50 раз больше строк.


Доступ к Б-деревьям, медленней, потому что для чтения даже одного значения из блока нужно просматривать пару килобайт данных (размер блока). Зато само время доступа падает как логарифм от количества записей по основанию, которое зависит от ветвистости дерева (которая может быть и переменной..). Но, как правило, количество ветвей будет порядка 100.

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


Вообще, я заметил, что MySQL, даже последних версий, не всегда правильно выбирает индексы, которые нужно использовать, особенно в случае составных индексов :). Поэтому в запросах, которые работают с составными индексами, крайне желательно писать FORCE INDEX(`combined`), а то производительность может отличаться в произвольное число раз, например в 50 :).
$topic = strtr($topic, array('mySQL' => 'MySQL'));
да, мне даже сначала показалось, что топик про mSQL
Намного лучшей стратегией является создание комбинированного индекса
Скажите это разработчикам NetCat. Уже которую неделю они «тестируют» наше предложение внести совместный индекс на поля, участвующие в ключевых запросах системы.
Кстати, раз уж все здесь. Скажите, оптимизатор достаточно умен, чтобы считать «IN (1)» как "= 1" и использовать составной индекс?
Я бы это делал в разделе с упрощением WHERE выражения, а не вводил такую логику в оптимизатор:

dev.mysql.com/doc/refman/5.0/en/where-optimizations.html

По ссылке выше об оптимизации, о которой Вы говорите, не написано, зато написано, что
MySQL performs a great many optimizations, not all of which are documented here.

Так что, возможно, он и делает эту оптимизацию :). А может и нет. Попробуйте посмотреть исходный код (в принципе, я думаю, достаточно посмотреть насчёт упоминания об этой оптимизации в комментариях :)).
1. в целях сравниловки думаю следует указать мощности, на которых производилось исследование.
2. я так понимаю статья как намек на высокопроизводительные системы — давай пиши про вставку/удаление/перезапись на подобных таблицах, будет оч полезно почитать
Спасибо за исследование. Интуитивно понимал, но не проверял
Блять.

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

Спасибо, Хабр.
спасибо за статью!
интересно было бы почитать про инсерты/апдейты, и получить еще рекомендаций по построению индексов етц
Я бы ещё добавил что разумный предел — 3-4 колонки для составных индексов. Больше — либо что то надо подумать в структуре бд (ибо если одни и те же WHERE с 4 колонками делаются — это как раз хорошее поле для оптимизации). Во вторых размер индекса будет большой и в третьих его регенирация при изменении данных будет весьма ощутима.

Например если есть 10 колонок по которым в разнобой делается выборка, то можно сделать несколько индексов на 2-3 колонках таких, которые будут оставлять как можно меньше данных. Т.е. это должны быть колонки где наиболее разношерстные данные. Таким образом если всего 1 млн записей, то после такого индекса на filesort будет оставаться, например, 100 при любой комбинации.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории