|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Здрасте, уважаемые! Есть таблица, достаточно широкая и с ~10 миллионами записей (чисто тестовые данные, будет больше). В ней есть столбец с очень низким кардиналити - порядка 80 вариантов на эти самые 10 лямов. Только инты. При навешивании простого btree уменьшение веса селекта падает с 570к до 420к. Недостаточно и понимаю, что дереву тут не место. Но битмапы, как я понял, в постгре нету. Вопрос: какой индекс стоит использовать в таком случае? ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 11:36 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Забыл добавить: Постгря 10. Партицирование не предлагать - таблица уже партицирована. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 11:39 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Johnson1893, А как партиционирована? Как распределены данные? Что вы хотите от индекса при такой кардинальности? Если надо с индексом прочитать 90% партиции, то лучше читать саму таблицу последовательно. У вас олтп, или аналитика? Что с параллелью? ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 11:44 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Johnson1893, репартицируйте вашу таблицу. первично (partition) по низкокардинальному полю, вторично (sub-partition) - как оно сейчас порезано на части. ну и нужно понимать, что секционирование будет к месту лишь в том случае, если условия фильтрации в запросах ложатся на схему секционирования. Чтобы не получилось, что таблицу вы порезали на "синее", "красное", "зеленое", а искать будете "теплое", "твердое", "квадратное". ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 12:18 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Johnson1893Здрасте, уважаемые! Есть таблица, достаточно широкая и с ~10 миллионами записей (чисто тестовые данные, будет больше). В ней есть столбец с очень низким кардиналити - порядка 80 вариантов на эти самые 10 лямов. Только инты. При навешивании простого btree уменьшение веса селекта падает с 570к до 420к. Недостаточно и понимаю, что дереву тут не место. Но битмапы, как я понял, в постгре нету. Вопрос: какой индекс стоит использовать в таком случае? Вы бы лучше реальное время работы сравнивали у запросов а не цены у explain. Вообще все индексы ставятся не для сферического коня в вакууме а для ускорения конкретных прикладных запросов. Вот от реальных запросов нужных вам и прыгайте, при низкой селективности как у вас самое быстрое будет параллельный seq scan в 4-8 потоков скорее всего просто при выборе по этому полю (но вообще это очень странный use case когда надо выбирать ТОЛЬКО по полю с кардиналити 80). -- Maxim Boguk dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 12:23 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Партицирована по месяцам, на три года (36 партиций). Всего 6 связанных партицированных таблиц (все партицированы одинаково). Первичная выборка идёт по месяцу (непосредственный ключ партиции), затем по полю, о котором вопрос (ид региона). То есть она и так уже партицирована по наименьшей кардинальности. Делать суб-партиции и получить вместо 216 партиций получить 17280 - не кажется мне охеренной идеей... Распределение значений до регионам достаточно равномерно, то есть выборка реально вернет не 90%, а около 1/80 всех записей партиции. Аналогично равномерно для другой части партиции. Про параллель всё просто. Её условно нет. Если вдруг она случается - оператору предусмотрено отрывание рук. Шутка, на самом деле её отсутствие будет гарантироваться бизнесом сервера. Возможно, в дальнейшем будут проверки, на исключение параллельности в БД. Не аналитика, но достаточно сложный запрос в plsql, возвращающий массив сложных UDT в массиве либо курсоре (для моего драйвера по сути не важно). От индекса я хочу получить достаточно быструю выборку по одному значению, по которой уже дальше пойдёт присоединение других таблиц. Ради этого готов вынести первоначальный запрос в with. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 12:36 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Johnson1893Партицирована по месяцам, на три года (36 партиций). Всего 6 связанных партицированных таблиц (все партицированы одинаково). Первичная выборка идёт по месяцу (непосредственный ключ партиции), затем по полю, о котором вопрос (ид региона). То есть она и так уже партицирована по наименьшей кардинальности. Делать суб-партиции и получить вместо 216 партиций получить 17280 - не кажется мне охеренной идеей... Распределение значений до регионам достаточно равномерно, то есть выборка реально вернет не 90%, а около 1/80 всех записей партиции. Аналогично равномерно для другой части партиции. Про параллель всё просто. Её условно нет. Если вдруг она случается - оператору предусмотрено отрывание рук. Шутка, на самом деле её отсутствие будет гарантироваться бизнесом сервера. Возможно, в дальнейшем будут проверки, на исключение параллельности в БД. Не аналитика, но достаточно сложный запрос в plsql, возвращающий массив сложных UDT в массиве либо курсоре (для моего драйвера по сути не важно). От индекса я хочу получить достаточно быструю выборку по одному значению, по которой уже дальше пойдёт присоединение других таблиц. Ради этого готов вынести первоначальный запрос в with. Параллельность я имел в виду параллельное выполнение запросов в базе силами нескольких ядер. При вашей кардинальности это скорее всего будет быстрее чем index или bitmap scan. А вообще показывайте запросы, показывайте результаты explain (analyze, costs, buffers, timing) WITH в такой ситуации вам только все замедлит. Вернуть 1/80 таблицы с наибольшей вероятностью будет быстрее именно так. -- Maxim Boguk dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 12:42 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Без индекса [2018-06-04 14:40:06] 500 rows retrieved starting from 1 in 2 s 154 ms (execution: 2 s 81 ms, fetching: 73 ms) С индексом [2018-06-04 14:40:38] 500 rows retrieved starting from 1 in 164 ms (execution: 94 ms, fetching: 70 ms) Снова без индекса [2018-06-04 14:41:42] 500 rows retrieved starting from 1 in 2 s 134 ms (execution: 2 s 80 ms, fetching: 54 ms) Да, выглядит впечатляюще, чёт я не подумал. Нужно, конечно, еще джоинами обмазаться и построением UDT (что ведет необходимость группировки), но в целом я удивлен, что планировка так ошиблась... Спасибо за совет! ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 12:45 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Maxim Boguk, На цифры особо смотреть не стоит, это только первая часть запроса... Дальше будет присоединен десяток таблиц, будет группировка и создание UDT. В целом существующий сейчас запрос (регионы в одной из присоединенных таблиц) просто сосёт по скорости. Вот пытаюсь как-то это дело прооптимизировать. Могу существующий запрос приложить, если нужно, чтобы имели представление, что за монстр там собирается... Запрос: Код: sql 1. 2. 3. 4. 5.
Эксплейн без индекса: постгряGather (cost=1000.00..527903.61 rows=27370 width=228) (actual time=179.305..1034.805 rows=32517 loops=1) Workers Planned: 2 Workers Launched: 2 Buffers: shared hit=273387 -> Append (cost=0.00..524166.61 rows=11404 width=228) (actual time=434.287..1008.551 rows=10839 loops=3) Buffers: shared hit=470488 -> Parallel Seq Scan on t_bill_2018_06 bb (cost=0.00..524166.61 rows=11404 width=228) (actual time=434.286..1007.756 rows=10839 loops=3) Filter: ((email IS NOT NULL) AND (period_id = 2) AND (region_id = 66)) Rows Removed by Filter: 2852020 Buffers: shared hit=470488 Planning time: 0.461 ms Execution time: 1074.754 ms Эксплейн с индексом: постгряAppend (cost=4895.24..424426.19 rows=27370 width=228) (actual time=39.549..156.154 rows=32517 loops=1) Buffers: shared hit=14255 read=732 I/O Timings: read=4.719 -> Bitmap Heap Scan on t_bill_2018_06 bb (cost=4895.24..424426.19 rows=27370 width=228) (actual time=39.548..152.745 rows=32517 loops=1) Recheck Cond: (region_id = 66) Filter: ((email IS NOT NULL) AND (period_id = 2)) Rows Removed by Filter: 234109 Heap Blocks: exact=14255 Buffers: shared hit=14255 read=732 I/O Timings: read=4.719 -> Bitmap Index Scan on t_bill_2018_06_region_id_index (cost=0.00..4888.40 rows=264528 width=0) (actual time=35.368..35.368 rows=266626 loops=1) Index Cond: (region_id = 66) Buffers: shared read=732 I/O Timings: read=4.719 Planning time: 0.932 ms Execution time: 158.062 ms ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 12:51 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Вообще, сейчас вот, используется такая портянка. Код с моими комментами и малость причесанный по именам переменных и стилю: осторожно, может вызвать приступ гнева Код: sql 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. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125.
Выдает такой вот план: explane [2018-06-04 14:58:58] 152 rows retrieved starting from 1 in 1 m 33 s 955 ms (execution: 1 m 33 s 931 ms, fetching: 24 ms) Код: sql 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. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152.
... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 13:00 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Johnson1893, Для просто запроса по условию - выборка 266626 строк за 35ms - вполне приличное время и вряд ли вы его сделаете быстрее. Общий простой запрос с допусловиями очевидно тратит время на Filter: ((email IS NOT NULL) AND (period_id = 2)) Rows Removed by Filter: 234109 Что намекает на мысль проанализировать что у нас селективно в этом условии первая часть или вторая. И в зависимости от этого сделать или составной индекс по (region_id, period_id) или условный индекс на (region_id) where (email IS NOT NULL). Это скорее всего даст вам в простом запросе 3-5кратный прирост. Быстрее вы его уже не сделаете. Разве что попробовать 10тую версию и настроить на большее количество воркеров на запрос (но для 200000 строк это особо прироста не даст). А вот с большим запросом надо думать. Как минимум там очень странное дело с LIMIT без ORDER BY. Я бы порекомендовал СНАЛАЧА в WITH сделать LIMIT без GROUP BY. А потом уже к этим 30 строка присоединять все эти ваши остальные таблицы и делать там array_agg уже не по всей простыне а только по уже заранее подобранным 30 строкам. -- Maxim Boguk dataegret.ru ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2018, 22:25 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Лимит там чисто для тестов на стороне сервера. Большой объем данных для тестов там ни к чему. Лимит уйдёт. Вопрос такой: что лучше, писать монструозный селектище с WITH, или писать простой селект по t_bill_base и дальше его циклом гонять и приселекчивать отдельно из кучи таблиц? Еще думаю попробовать сложный селект без группировки и прямого преобразования в UDT, а уже по нему цикл и преобразование... Но надо экспериментировать... ... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2018, 06:36 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Maxim Boguk, period_id это ключ партиции, и в выбранной партиции он всегда 2. Использовать его в индексе бессмысленно. email is not null это уже селективный, но конкретно в этом запросе интересуют ТОЛЬКО записи с мейлом. В среднем их около 30%, равномерности никакой. Опять же, кардиналити еще ниже и смысл навешивать индекс не понятный... Вот и мучаюсь. И чё от запроса хочу знаю, и работает всё в нескольких вариантах. А с оптимизацией беда даже на тестовой выборке... Думал уже передавать на сервер в чистом виде и уже там собирать, но наархитектурено так, что по-простому уже не получится (объекты не плоские), а переделывать всё - просто нет времени. ... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2018, 06:43 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Johnson1893Maxim Boguk, period_id это ключ партиции, и в выбранной партиции он всегда 2. Использовать его в индексе бессмысленно. email is not null это уже селективный, но конкретно в этом запросе интересуют ТОЛЬКО записи с мейлом. В среднем их около 30%, равномерности никакой. Опять же, кардиналити еще ниже и смысл навешивать индекс не понятный... Вот и мучаюсь. И чё от запроса хочу знаю, и работает всё в нескольких вариантах. А с оптимизацией беда даже на тестовой выборке... Думал уже передавать на сервер в чистом виде и уже там собирать, но наархитектурено так, что по-простому уже не получится (объекты не плоские), а переделывать всё - просто нет времени. Так смотрите - вы хотите тяжелую аналитику по миллионам счетов. Такие вещи не в online считают а заказывают и ставят считаться в offline с получением отчета на почту. Те цифры что вы привели в полном плане - вполне разумные учитывая сколько там строк пересчитывается. Исходите из того что где то миллион строк в секунду можно что то сделать (select / join / etc) и прикиньте сколько там у вас всего строк обрабатывается. По email - вам УСЛОВНЫЙ блин индекс нужен вида on(region_id) WHERE email is not null и конкретно простой приведенный вами пример оно ускорит. Далее - прекратите WITH использовать не по делу... если у вас результат WITH подзапроса используется 1 раз - вы его не поделу используете, это оптимизационный барьер для базы (причем специально сделанный). Как минимум первые 3 WITH - должны быть одним запросом - тогда скорее всего получится более эффективно параллельные запросы использовать. Далее - поставьте больше параллельных workers и более дешевый их запуск в конфиге базы. Ну и попробуйте 10 версию базы вместо 9.6 (она лучше умеет параллельное выполнение запросов). ... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2018, 09:51 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Maxim Boguk, Спасибо за разъяснения! Да, с кучей WITH вышло не удачно, не понимал для чего оно. Начал его использовать из-за конкретной проблемы - нельзя делать вложенную аггрегацию array_agg. "И тут Остапа понесло!". Версия постгри и так 10. Про условный индекс почитаю плотнее, но кажется, суть уловил, спасибо! Задание и так заказное, через "таск менеджер". Выполняется оно в любом случае дольше, чем грузится из базы. На почту результат не получится, специфика бизнес-логики и постановки. ... |
|||
:
Нравится:
Не нравится:
|
|||
06.06.2018, 06:30 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
авторperiod_id это ключ партиции, и в выбранной партиции он всегда 2. Использовать его в индексе бессмысленно. короче, давай ты просто попробуешь index (region_id, period_id ) и покажешь exdplain ... |
|||
:
Нравится:
Не нравится:
|
|||
06.06.2018, 14:29 |
|
Какой использовать индекс за столбцов с низким кардиналити?
|
|||
---|---|---|---|
#18+
Ivan Durak, Сделать смогу только завтра, данные грохнули, надо заливать заново... Пока переписал функцию, избавился вообще от WITH, правда с подзапросом и кривым джойном - не придумал как избежать вложенной аггрегации по-другому. explain Код: sql 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. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98.
запрос Код: sql 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. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107.
... |
|||
:
Нравится:
Не нравится:
|
|||
07.06.2018, 08:59 |
|
|
start [/forum/topic.php?fid=53&msg=39654767&tid=1995739]: |
0ms |
get settings: |
10ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
41ms |
get topic data: |
11ms |
get forum data: |
3ms |
get page messages: |
55ms |
get tp. blocked users: |
1ms |
others: | 314ms |
total: | 457ms |
0 / 0 |