Комментарии 18
Однако после анализа самых частых sql–запросовИмхо, с этого надо было начинать.
+4
Не совсем понятно, причем тут вообще селективность. Какой бы идеальной она не была, если фильтр запроса пропустил хоть одну колонку в последовательности индекса, не видать index seek'ов как своих ушей.
В данном случае первый запрос фильтровал по дате, ему только дата и нужна была в индексе, если бы это был SqlServer, то сообщение спокойно можно было бы вообще пихать в инклюды.
Второй же запрос наоборот чхал на дату, и от текущего индекса ему пользы никакой, всё равно условный «бинарный поиск» не может отработать, тк данные отсортированы сначала по дате, и только на следующем уровне уже по сообщению.
Так что поведение более чем ожидаемо. Для таких диаметрально противоположных запросов надо просто два отдельных индекса.
Конечно, если в итоге оказывается, что фильтр по дате никогда и не используется, то и проблема не стоит, но и новый индекс тогда не особо полезен, тк в нем нет типа сообщения, и чтобы его проверить, придется лазить в саму таблицу. Хотя на этом конкретном примере скорее всего тексты сообщений не пересекаются между типами (обратное для логов было бы странно :)), так что фильтр по типу сообщения скорее всего вообще никогда ничего в реальности не фильтрует и его можно спокойно убрать.
Ну а если еще и ищут в 99% случаев только тип 'error' то вообще можно сделать фильтрованный индекс, который был бы маленьким, и позволял бы искать ошибки быстро, а просто логи читать можно было бы как раньше, по дате
В данном случае первый запрос фильтровал по дате, ему только дата и нужна была в индексе, если бы это был SqlServer, то сообщение спокойно можно было бы вообще пихать в инклюды.
Второй же запрос наоборот чхал на дату, и от текущего индекса ему пользы никакой, всё равно условный «бинарный поиск» не может отработать, тк данные отсортированы сначала по дате, и только на следующем уровне уже по сообщению.
Так что поведение более чем ожидаемо. Для таких диаметрально противоположных запросов надо просто два отдельных индекса.
Конечно, если в итоге оказывается, что фильтр по дате никогда и не используется, то и проблема не стоит, но и новый индекс тогда не особо полезен, тк в нем нет типа сообщения, и чтобы его проверить, придется лазить в саму таблицу. Хотя на этом конкретном примере скорее всего тексты сообщений не пересекаются между типами (обратное для логов было бы странно :)), так что фильтр по типу сообщения скорее всего вообще никогда ничего в реальности не фильтрует и его можно спокойно убрать.
Ну а если еще и ищут в 99% случаев только тип 'error' то вообще можно сделать фильтрованный индекс, который был бы маленьким, и позволял бы искать ошибки быстро, а просто логи читать можно было бы как раньше, по дате
+2
Если будет два индекса на разные колонки, тогда модификация данных будет хуже выполняться
+1
а от одного индекса модификация не стала «хуже»?
и вообще, логи модифицировать никто не должен.
и вообще, вот эти «лучше/хуже» просчитываются на этапе проектирования приложения. но до этого надо ещё подрасти.
и вообще, логи модифицировать никто не должен.
и вообще, вот эти «лучше/хуже» просчитываются на этапе проектирования приложения. но до этого надо ещё подрасти.
+1
… и что? Абстрактное "хуже выполняться" никому не интересно, интересны реальные метрики: вот мы добавили индекс, наши типовые запросы на чтение ускорились на столько-то процентов (или нет), наши типовые запросы на запись замедлились на столько-то процентов (или нет), вот абсолютные значения на всякий случай тоже.
Может вам вообще нужна append-only БД, где индексы строятся отдельным процессом, кто ж вас знает.
+2
Выгрузить таблицу log куда-то в доступное место в csv можно?
+1
Офтоп: выборку по диапазону datetime лучше в общем соучае делать `date >= '2018-03-24 00:00:00' AND 'date' < '2018-03-25 00:00:00'` Это застрахует от изменения в точности представления datetime.
+3
НЛО прилетело и опубликовало эту надпись здесь
В Oracle с этим все легко и просто:
1. Можно использовать композитное секционирование, например: интервальное секционирование по датам datetime и подсекции по message. Допустим, каждая секция содержит только одни сутки, и каждая подсекция только свой message. В таком случае индексы вообще будут не нужны, поэтому такой вариант обычно и рекомендуется для логов, т.к. там нагрузка в основном write-only.
2. если лидирующее поле/поля в индексе имеет небольшое количество разных значений и в запросе нет по нему предиката, но есть хороший селективный предикат по второму полю из индекса, то может использоваться Index Skip Scan
1. Можно использовать композитное секционирование, например: интервальное секционирование по датам datetime и подсекции по message. Допустим, каждая секция содержит только одни сутки, и каждая подсекция только свой message. В таком случае индексы вообще будут не нужны, поэтому такой вариант обычно и рекомендуется для логов, т.к. там нагрузка в основном write-only.
2. если лидирующее поле/поля в индексе имеет небольшое количество разных значений и в запросе нет по нему предиката, но есть хороший селективный предикат по второму полю из индекса, то может использоваться Index Skip Scan
0
Подводя итог, скажу, что целью статьи было вовсе не создание системы логов как таковой, а в первую очередь донесение до читателя той мысли, что не всегда ставить селективный атрибут влево – это хорошо.
Логи выступали лишь в качестве примера, и судя по комментариям, пример получился неудачный. Но на данный момент ничего лучше в голову не приходит
Логи выступали лишь в качестве примера, и судя по комментариям, пример получился неудачный. Но на данный момент ничего лучше в голову не приходит
0
Вам уже сказали: дело не в "селективности" атрибута, а в том, под какие задачи вы оптимизируете хранилище. В вашем случае оптимизация была под одни задачи, а в реальности ожидались другие. Кнут передает вам привет.
+1
Когда речь идет о том, что первым должен стоять самый селективный атрибут, имеется в виду самый селективный атрибут из запроса, а не из таблицы. Странно индексировать таблицу по одному полю, а фильтровать в запросе по другому, но именно это вы в своей статье и продемонстрировали.
В вашем запросе используется два поля: `message` и `type`, если бы вдруг написали, что в индексе именно `type` должен стоять на первом месте, а `message` на втором и привели бы обоснование с примером, то такое содержимое соответствовало бы заголовку статьи, а пока — извините, вы не до конца понимаете, о чем пишете.
В вашем запросе используется два поля: `message` и `type`, если бы вдруг написали, что в индексе именно `type` должен стоять на первом месте, а `message` на втором и привели бы обоснование с примером, то такое содержимое соответствовало бы заголовку статьи, а пока — извините, вы не до конца понимаете, о чем пишете.
+1
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Почему ставить наиболее селективные колонки в префикс составного индекса – это не всегда хорошо