|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Читая форумы я натолкнулся на факт что Mysql умеет использовать индексы для поиска уникальных значений. И в принципе это логично если уникальных значений не много. PostgreSQL так не умеет. Подсчет уникальных значений в большой таблице достаточно частый головняк для Postgresql DBA так как любит тормозить. Пришлось обьяснять. (настройки по умолчанию кроме work_mem 32MB / shared_buffers 2GB). Подготовка данных: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8.
Теперь смотрим на скорость select count(distinct ...) from test_table (select distinct будет иметь туже приблизительно скорость): (все тесты проводились 3-4 раза для контроля стабильности результатов) Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23.
На выходе имеем 25+ секунд на любой вариант с замедлением при росте количества уникальных значений. Теперь быстрая реализация использующая индексы по полям и рекурсивный запрос: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65.
В итоге получена реализация distinct которая эффективно использует индексы по полю и в случаях не слишком большого количества уникальных значений работает принципиально быстрее. Я кстати ожидал квадратичной деградации этого алгоритма... но на практике наблюдается линейная (база оказалась умнее чем я ожидал). Собственно запрос для тех кто знает как работает WITH RECURSIVE простой. Все сложности только с обходом ограничений на то что можно использовать с WITH RECURSIVE а что нельзя (нельзя: аггрегаты и подзапросы по накопительной таблице). PS: 8.4+ only естественно. PPS: если непонятно как оно устроено пишите я попробую более подробно обьяснить. PPPS: аналогично можно реализовать эффективные запросы вида select max(cdate),status from big_table group by status и подобные им <BR>--<BR>Проект с базой но без DBA всеравно что автопарк без штатного автомеханика. Ездит пока все не сломается.<BR> http://mboguk.moikrug.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 14:31 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Maxim Boguk, гут) ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 14:54 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Maxim Boguk Я кстати ожидал квадратичной деградации этого алгоритма... но на практике наблюдается линейная (база оказалась умнее чем я ожидал).насколько я помню свои тесты - оно только поначалу линейно. а с некоторого порога резко лезет вверх. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 15:41 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Maxim Boguk, немного переписал Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.
деградация линейная от кол-ва различных элементов. а внутри этой линии логарифм от размера таблицы ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 16:03 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
qwwq, тут лезть РЕЗКО вверх может только, если у вас где то памяти какой-то не хватило. а так всё довольно гладко k * lg( N ) k - кол-во различных N - размер таблицы ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 16:09 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Хотел предложить добавить на wiki, но там уже есть %) http://wiki.postgresql.org/wiki/Loose_indexscan ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 17:13 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
ЁшХотел предложить добавить на wiki, но там уже есть %) http://wiki.postgresql.org/wiki/Loose_indexscan черт все придумано до нас... интересно почему я раньше этой ссылки не видел ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 17:43 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Misha Tyurinqwwq, тут лезть РЕЗКО вверх может только, если у вас где то памяти какой-то не хватило. а так всё довольно гладко k * lg( N ) k - кол-во различных N - размер таблицы вспомнил. немного другой случай смотрел :0) /topic/876457&pg=1&hl=recursive - из-за чего там лезло - не помню. да, и еще забавно было, помню, если в рекурсивном запросе брать не всю work_table (1 запись на каждой иттерации), а _специально_ сказать только LIMIT 1 - то EXPLAIN ANALYZE много быстрее получался. а вот насчет реальной скорости запросов не помню. точно не вспомню, надо смотреть записнушки. вот примерно скажем если в стартовом примере автора этого треда сделать Код: plaintext
а вот в том случае - сильно менялась цена, хотя work_table тоже была однозаписна на каждой итерации. ЗЫ а про индексы для свёртки уникальных - надо просто посмотреть на индекс как на отдельную (и _полную_) таблицу ключей - и сразу станет понятно, что и как считать уже имеющимися у оптимайзера методами 11318626. не понимаю, почему не сделано. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 18:24 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
qwwqMisha Tyurinqwwq, тут лезть РЕЗКО вверх может только, если у вас где то памяти какой-то не хватило. а так всё довольно гладко k * lg( N ) k - кол-во различных N - размер таблицы вспомнил. немного другой случай смотрел :0) /topic/876457&pg=1&hl=recursive - из-за чего там лезло - не помню. а там лезло из-за того, что там другая, уже не линейная зависимость. и при "дальних" сканах уже много индекса перебирается. там k^2 * log(N) ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 19:18 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
[quot qwwq]Misha Tyurinqwwq, ЗЫ а про индексы для свёртки уникальных - надо просто посмотреть на индекс как на отдельную (и _полную_) таблицу ключей - и сразу станет понятно, что и как считать уже имеющимися у оптимайзера методами 11318626 . не понимаю, почему не сделано. потому что индекс - это не таблица. MVCC тут у нас такой. можно явно, на триггерах например, поддерживать аналогичные структуры и денормализацию подобную в целом ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 19:21 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Misha Tyurin а там лезло из-за того, что там другая, уже не линейная зависимость. и при "дальних" сканах уже много индекса перебирается. там k^2 * log(N)это я тогда вычислил /*быстро наступает инфляция новых значений*/ - но забыл. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 21:10 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Misha Tyurinпотому что индекс - это не таблица. MVCC тут у нас такой. можно явно, на триггерах например, поддерживать аналогичные структуры и денормализацию подобную в целома нам нужны не актуальные значения, а заведомо накрывающее мн-во значений. это что касаемо транзакционности [и не версионности индексов ]. избыточность нам не мешает (вернее не принципиально - только на скорость) а что касается скорости вычитки мн-ва значений (а не мн-ва всех адресов) малоселективного индекса - я думаю это много быстрее, хотя помню с трудом способы организации/читки индексного дерева - смотрел только в общих чертах. PS что касается поддержания - то как правило в нормально спроектированной базе все эти таблицы "ключей" всегда существуют. в виде т.н. справочников и fk гарантию их накрытия контролирует. т.е. их даже не надо триггерно поддерживать. ... |
|||
:
Нравится:
Не нравится:
|
|||
23.09.2011, 21:21 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Maxim Boguk, Здесь выбор строк с уникальной группой полей Вы советовали использовать для группы этот же метод. Не моглы бы Вы привести пример для группы полей. Спасибо. ... |
|||
:
Нравится:
Не нравится:
|
|||
28.05.2013, 10:50 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Gold_Maxim Boguk, Здесь выбор строк с уникальной группой полей Вы советовали использовать для группы этот же метод. Не моглы бы Вы привести пример для группы полей. Спасибо. так тоже самое по сути: Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
тут предполагается что a,b,c все not null иначе не понятно какой там distinct должен быть (считать ли nulls равными или нет) ну и естественно индекс по a,b,c нужен тестирование: на 9.2 еще и index only scan во всю силу работает: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45.
ускорение в 100 раз при 1331 уникальных значениях в таблице на миллион записей... чем больше таблица и чем меньше distinct values - тем будет быстрее... если таблица широкая и полей в ней много то лучше поставить hstore и сделать чуть по другому: Код: plsql 1. 2. 3. 4. 5. 6. 7. 8.
Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30.
Скорость не хуже чем у первого варианта но всегда гарантированный index only scan А на широкой таблице легко может быть раз в 10 быстрее даже... Но писать конечно менее удобно. Как то так. -- Maxim Boguk Senior Postgresql DBA http://www.postgresql-consulting.ru/ ... |
|||
:
Нравится:
Не нравится:
|
|||
28.05.2013, 12:47 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Maxim Boguk, Спасибо!!! ... |
|||
:
Нравится:
Не нравится:
|
|||
28.05.2013, 15:21 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Maxim Boguk, Максим, тема старая, но хотел бы спросить. например у меня одна таблица с уникальным id 15000 записей и вторая таблица, в которой каждому id соответствуют тысячи id_org 4млн записей я делаю select distinct t1.id, t2.id_org, t1.name, t1.status, t1.second_name from table1 t1 join table2 t2 on t2.t1_id=t1.id получаю 1млн записей делается по факту distinct 4млн записей Скажите, можно ли сюда приделать ваш способ и им выбирать уникальные t2.id_org для каждого t1.id? ... |
|||
:
Нравится:
Не нравится:
|
|||
09.04.2021, 17:26 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
kliff Maxim Boguk, Максим, тема старая, но хотел бы спросить. например у меня одна таблица с уникальным id 15000 записей и вторая таблица, в которой каждому id соответствуют тысячи id_org 4млн записей я делаю select distinct t1.id, t2.id_org, t1.name, t1.status, t1.second_name from table1 t1 join table2 t2 on t2.t1_id=t1.id получаю 1млн записей делается по факту distinct 4млн записей Скажите, можно ли сюда приделать ваш способ и им выбирать уникальные t2.id_org для каждого t1.id? Не понял вашего описания задачи... вы бы хоть таблицы обьявили... я даже не могу написать запрос который бы прояснил бы ситуацию на счет стоит или нет... В общем случае если вы смотрели на пост - на миллионе distinct значений уже толку нет особо. Особенно если на входе 4М а на выходе 1М (было бы на входе 400М а на выходе 1M - ситуация была бы другая). -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
09.04.2021, 17:57 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Maxim Boguk, вот все описание select distinct t1.id, t2.id_org, t1.name, t1.status, t1.second_name from table1 t1 join table2 t2 on t2.t1_id=t1.id вопрос можно ли сделать через рекурсию, ведь дубли только в table2 ... |
|||
:
Нравится:
Не нравится:
|
|||
09.04.2021, 19:03 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
kliff Maxim Boguk, вот все описание select distinct t1.id, t2.id_org, t1.name, t1.status, t1.second_name from table1 t1 join table2 t2 on t2.t1_id=t1.id вопрос можно ли сделать через рекурсию, ведь дубли только в table2 ну так оно очевидно же переписывается в distinct по одной таблице где дубли select t1.id, t2.id_org, t1.name, t1.status, t1.second_name from table1 t1 join (select distinct t1_id, id_org FROM table2) AS t2 on t2.t1_id=t1.id -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
09.04.2021, 19:07 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
Maxim Boguk, да, так пробовал. результат по скорости не устраивает, но возможно это максимум что можно сделать. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.04.2021, 08:06 |
|
Быстрый подсчет distinct values по индексированным полям
|
|||
---|---|---|---|
#18+
kliff Maxim Boguk, да, так пробовал. результат по скорости не устраивает, но возможно это максимум что можно сделать. Смотря что именно вы делали... такой distinct или его оптимизацию по вышеописанному треду? (прочем при 1 уникальном на 4 строки - толку 100% не будет... надо хотя бы 1 к 100 чтобы толк был). -- Maxim Boguk лучшая поддержка PostgreSQL: dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
10.04.2021, 17:21 |
|
|
start [/forum/topic.php?fid=53&fpage=13&tid=1994090]: |
0ms |
get settings: |
7ms |
get forum list: |
12ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
29ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
53ms |
get tp. blocked users: |
2ms |
others: | 329ms |
total: | 453ms |
0 / 0 |