powered by simpleCommunicator - 2.0.18     © 2024 Programmizd 02
Map
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Как оптимизировать выборку по диапазону?
6 сообщений из 31, страница 2 из 2
Как оптимизировать выборку по диапазону?
    #40134108
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LiYing
Partition pruning при беглом ознакомлении показалось многообещающим, но обнаружилась печалька

А вот тут надо хорошо в затылке почесать, что важнее. FK ведь можно и сэмулировать на триггерах.
...
Рейтинг: 0 / 0
Как оптимизировать выборку по диапазону?
    #40134132
LiYing
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Akina
А вот тут надо хорошо в затылке почесать, что важнее. FK ведь можно и сэмулировать на триггерах.

Это что-то типа такого? https://stackoverflow.com/questions/47230968/how-to-make-a-trigger-work-like-a-foreign-key
Если нет, то можно примерчик такого эмулирования?
...
Рейтинг: 0 / 0
Как оптимизировать выборку по диапазону?
    #40134171
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LiYing
Это что-то типа такого?

Угу, именно. То, что обычно делается системно, выполняется вручную триггерами. Конечно, полной эмуляции так не получить, но случаи, когда эмуляция невозможна, достаточно редки и экзотичны. Другой вопрос - надо ли реально, ведь поддержка такой эмуляции намного сложнее, и надо иметь очень серьёзные основания для её применения.

Есть и другие способы ускорения. Например, предрасчёт - предварительная агрегация. Например, посуточная, по дате и контрагенту. И соответственно запрос слать в предрасчётную таблицу, где будет явно поменьше записей.
...
Рейтинг: 0 / 0
Как оптимизировать выборку по диапазону?
    #40135383
VDeltsov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
авторLiYing,

SELECT d.period p, COUNT(DISTINCT c.id_mkd) c1, COUNT(c.id) c2
FROM data_sgrc d
INNER JOIN contragents c ON d.id_contragent=c.id
WHERE d.period='2021-10-01'
GROUP BY p


Я бы для конкретно этого запроса сделал:
либо индекс data_sgrc по колонокам period + id_contragent, а не наоборот, как тут предлагали.
Но индекс такой нужен только при условии, что в реальном запросе из этой таблицы берется только дата и id_contragent, а другие колонки не берутся. Тогда после сканирования куска индекса мы в таблицу вообще не лезем.

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

В MS SQL Server я под такое сделал не партиционирование, а кластеризованный индекс по дате + ID, то есть таблица сама является индексом посортированным по дате + ID. Поэтому все запросы за любой период - день, месяц, год - всегда сканируют только нужную часть таблицы. Это было просто чудом. Есть ли такой в MySQL сомневаюсь. Вам тогда партиционирование по дате, как некий аналог этого.

Если уж совсем надо быстро, то я бы переписал запрос так, чтобы сначала просуммировать исходную таблицу, а уже потом на маленьком просуммированном наборе присоединять справочник.

SELECT d.period p, COUNT(DISTINCT c.id_mkd) c1, sum(c3) c2
from (
SELECT d1.period p, d1.id_contragent, count(*) as c3
FROM data_sgrc d1
WHERE d1.period='2021-10-01'
group by d1.period, d1.id_contragent
) d
INNER JOIN contragents c ON d.id_contragent=c.id
GROUP BY d.period
...
Рейтинг: 0 / 0
Как оптимизировать выборку по диапазону?
    #40135482
LiYing
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
VDeltsov,

спасибо за советы!
Протестировал предложенный запрос:
№1 для одного месяца
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT d.p p, COUNT(DISTINCT c.id_mkd) c1, sum(c3) c2
from (
SELECT d1.period p, d1.id_contragent, count(*) as c3
FROM data_sgrc d1
WHERE d1.period='2021-10-01'
group by d1.period, d1.id_contragent
) d
INNER JOIN contragents c ON d.id_contragent=c.id
GROUP BY d.p


idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra1PRIMARY<derived2>nullALLnullnullnullnull110843100.00Using where; Using filesort1PRIMARYcnulleq_refPRIMARYPRIMARY4d.id_contragent1100.00null2DERIVEDd1nullindexid_contr_perid_contr_per9null110843610.00Using where; Using index

№2 для трех месяцев
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT d.p p, COUNT(DISTINCT c.id_mkd) c1, sum(c3) c2
from (
SELECT d1.period p, d1.id_contragent, count(*) as c3
FROM data_sgrc d1
WHERE d1.period BETWEEN '2021-10-01' AND '2021-12-01'
group by d1.period, d1.id_contragent
) d
INNER JOIN contragents c ON d.id_contragent=c.id
GROUP BY d.p


idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra1PRIMARY<derived2>nullALLnullnullnullnull123147100.00Using where; Using filesort1PRIMARYcnulleq_refPRIMARYPRIMARY4d.id_contragent1100.00null2DERIVEDd1nullindexid_contr_perid_contr_per9null110843611.11Using where; Using index; Using temporary
№1 > Query Time: 1,08s
№2 > Query Time: 2,627s
Т.е. запросы выполняются еще дольше. Первый, для периода в 1 месяц, в 2 раза дольше, а второй - незначительно, но все равно дольше.
...
Рейтинг: 0 / 0
Как оптимизировать выборку по диапазону?
    #40135860
VDeltsov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
LiYing, увидел, что у вас тут миллион клиентов, поэтому быстрее чем за секунду вы тут вряд ли получите.

Самый быстрый вариант - это исключительно для тестов сделать два индекса, чтобы узнать самое минимальное время выполнения:
data_sgrc по колонкам period + id_contragent
contragents по колонкам id + id_mkd

При этом таблицы вообще не будут считываться, только соединение индексов.
Посмотреть, какое будет минимальное время второго выполнения, когда нужные куски индекса будут уже в памяти.
Если это итак будет в районе 1 секунды, то будет ясно, что это - предел.

И останется только подсказками попробовать два варианта соединения - hash join (и full index scan на таблицу клиентов) и nested loop (на таблицу клиентов). Как в MySQL делать подсказки - не знаю.

Кстати, в MySQL есть подсказка типа PARALLEL 8, как в ORACLE, или option (maxdop 8), как в MS SQL?

Следующий вариант, боюсь посоветовать, так как за колоночные таблицы в соседних ветках меня Ролин Хун затролллил.
Ровно аналогичный запрос к колоночным таблицам MS SQL Server, где в таблице фактов 440 млн строк, в таблице клиентов 1,8 млн.
В результате фильтра по дате (за год) получаю 60 млн строк, в результате первой группировки получают 1 миллион строк (миллион сочетаний дата+клиент), затем соединяю на клиентов и группирую по дням, делаю distinct id_mkd - получают 335 строк.
И всё это за 0,5 секунд при максимальной параллельности на 12 ядер процессора.
Если брать за один большой день (31 декабря), где 700 000 строк данных, то результат будет 0,090 секунд.
На одном старом процессоре (2006 года выпуска) с отключенной параллельностью: 2 секунды (для 60 млн строк) и 0,260 секунд (для 700 тыс строк).

При этом никакого партиционирования, никаких дополнительных индексов вообще не требуется.
Все данные с сжатом в 20 раз виде итак помещаются в память.

Но это всё в MS SQL Server в колоночных таблицах.

В MySQL колоночные таблицы есть только в MariaDB в виде отдельно подключаемого модуля, и только в Линуксе, и еще и ним надо научиться работать. Но зато OLAP-запросы будут супер быстрыми. При условии, что вставляете данные пачками, а не по одной.
Если попробуете их - расскажите тут или в моей ветке https://www.sql.ru/forum/1342038/
...
Рейтинг: 0 / 0
6 сообщений из 31, страница 2 из 2
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Как оптимизировать выборку по диапазону?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали тему (1): Анонимы (1)
Читали форум (1): Анонимы (1)
Пользователи онлайн (9): Анонимы (6), Yandex Bot, Bing Bot 1 мин., RePredeclared 5 мин.
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]