|
|
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#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. План у него получается следующий (опять таки кусок касающийся этой части запроса): Код: 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. В сумме он выполняется 55 секунд. И происходит это из-за того что GroupAggregate выполняется 327 раз. Соответственно вопрос почему она не материализует GroupAggregate ? Cost же у него запредельный. Estimate маленький. Или у PostgreSQL вообще нет такой возможности как materialize подзапроса и будет проблема в случае: A (маленькая таблица, ключ k0) LJ B (огромная таблица, ключ k0, поле f0 без индекса) ON A.k0 = B.k0 LJ SQ (маленький но долго выполняемый подзапрос с ключом k0) ON SQ.k0 = B.f0 Потому как у нее 2 варианта или высчитать SQ, а затем right join'ить с B что будет очень долго так как придется бежать по B (индекса там напомню нет, да и результат будет большой так что и индекс не поможет), после чего уже hash join'ить с A (план будет очень медленным) или (то что мы видим тут) для всех A, ищем все записи B и для каждой (! так как materialize'а нет) из них выполняем SQ после чего right join'им результат с B (план также будет медленным из-за многочисленного выполнения SQ). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 15:13 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Я вообще правильно понимаю что во втором случае (и собственно в первом), она должна сделать так Hash Right Join Hash Cond SQ.k0 = B.f0 GroupAggregate (допустим группирующий подзапрос с таблицей SQ) Hash Nested Left Join Seq scan A Index scan B on индекс по k0 Index cond : B.k0 = A.k0 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 15:38 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 15:39 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_JunkieNitro_Junkie, Код: plsql 1. 2. 3. 4. 5. 6. 7. 8. Проверил на других запросах, именно так она и должна делать, но почему здесь ее клинит загадка... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 15:58 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, закиньте этот group by в WITH блок и будет вам материализация. Но у меня есть идея почему он не материализует. У вас функция ANYVALUE(1) случайно не volatile? --Maxim Boguk www.postgresql-consulting.ru ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 15:59 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Maxim BogukNitro_Junkie, закиньте этот group by в WITH блок и будет вам материализация. Но у меня есть идея почему он не материализует. У вас функция ANYVALUE(1) случайно не volatile? --Maxim Boguk www.postgresql-consulting.ru Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. Я вообще наблюдаю странное явление природы. В приложении запрос показывает такой план, запускаю в pgAdmin план уже нормальный, чудо какое-то... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 16:03 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Воообще совет... в таких ситуациях зачастую проще помочь планировщику и частично зафиксировать нужный вам план через WITH (в тех частях где вам 100% materialize нужен). Ну и понимать что с стандартными настройками базы она только до 8 joins разворачивает/сворачивает а дальше начинается GEQO и угадает он с планом или нет никто не знает. Так что для сложных запросов еще полезно join_collapse_limit/from_collapse_limit поднять слегка. --Maxim Boguk www.postgresql-consulting.ru ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 16:11 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Maxim BogukВоообще совет... в таких ситуациях зачастую проще помочь планировщику и частично зафиксировать нужный вам план через WITH (в тех частях где вам 100% materialize нужен). Ну и понимать что с стандартными настройками базы она только до 8 joins разворачивает/сворачивает а дальше начинается GEQO и угадает он с планом или нет никто не знает. Так что для сложных запросов еще полезно join_collapse_limit/from_collapse_limit поднять слегка. --Maxim Boguk www.postgresql-consulting.ru Проблема в том что 100% materialize тяжеловато угадать. Кстати словил ту же проблему на совсем простом запросе, то есть на GEQO не спишешь: Код: 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. И кстати понял почему в pgAdmin не повторялось. Я когда временную таблицу (t_12) сохранял в постоянную чтобы в pgAdmin запустить, для последней не сделал VACUUM ANALYZE. Тогда postgres думал что записей 1540, а не 327 и план правильный был: Код: 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. Сделал VACUUM ANALYZE для этой t_12 и план стал : Код: 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. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 16:27 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Хм... Помогает уменьшение join_collapse_limit до 2: Код: plsql 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. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 16:35 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Хотя в общем-то логично что помогает, но управлять порядком join'ов мягко говоря не хочется. И в принципе если взглянуть на 2 плана то у неэффективного cost ниже. Что очень странно с учетом того что она знает что ей нужно 327 loops сделать, и почему-то cost GroupAggregate'а она не умножает на 327 :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 16:41 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, В общем похоже придется CTE делать, но у меня возникла тогда такая мысль. Ведь она CTE считает до выполнения запроса, а можно заставить ее рассчитать статистику по этому CTE ? Потому как подзапросы основное где postgresql ошибается со статистикой... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 16:53 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, 327 повторов уже заложены в cost -> GroupAggregate (cost=50099.52..50101.14 rows=6 width=35) (actual time=171.638..172.528 rows=322 loops=327)" насколько я понимаю. Разница в планах в том что Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. вместо rows=0 получится rows=1 - медленный план станет более быстрым... а в такой ситуации сложно ожидать стабильного поведения планировщика. --Maxim Boguk www.postgresql-consulting.ru ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 16:54 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Maxim BogukNitro_Junkie, 327 повторов уже заложены в cost -> GroupAggregate (cost=50099.52..50101.14 rows=6 width=35) (actual time=171.638..172.528 rows=322 loops=327)" насколько я понимаю. Разница в планах в том что Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. вместо rows=0 получится rows=1 - медленный план станет более быстрым... а в такой ситуации сложно ожидать стабильного поведения планировщика. --Maxim Boguk www.postgresql-consulting.ru Убрал условие c batchUserInvoiceDetail: Код: plsql 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. Хороший план с join_collapse 2: Код: 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. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 17:07 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Maxim Boguk327 повторов уже заложены в cost -> GroupAggregate (cost=50099.52..50101.14 rows=6 width=35) (actual time=171.638..172.528 rows=322 loops=327)" насколько я понимаю. Сделала с CTE: Код: 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. Cost все равно 50к, так что не уверен что loops в неэффективном плане в него включены. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 17:13 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Maxim Boguk327 повторов уже заложены в cost Код: plaintext 1. Это просто констатация фактически пройденных циклов (вторая скобка). Планировщик использует предполагаемое кол-во записей. @Nitro_Junkie , а вы могли бы указать версию PostgreSQL и измененную конфигурацию? Статистика свежая на таблицах? Если они временные, то их надо явно анализировать, т.к. они не видны `autovacuum` демону. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 18:06 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorovMaxim Boguk327 повторов уже заложены в cost Код: plaintext 1. Это просто констатация фактически пройденных циклов (вторая скобка). Планировщик использует предполагаемое кол-во записей. @Nitro_Junkie , а вы могли бы указать версию PostgreSQL и измененную конфигурацию? Статистика свежая на таблицах? Если они временные, то их надо явно анализировать, т.к. они не видны `autovacuum` демону. "PostgreSQL 9.3.4, compiled by Visual C++ build 1600, 64-bit" Статистика естественно свежая. Более того когда она не свежая, планировщик лучше работает :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 18:18 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Ах... Вы используете одни и те же алиасы таблиц в разных частях запроса. Я не уверен, к какой `t0` привязывается планировщик в разных частях запроса: Код: 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. Тот факт, что `join_collapse_limit` помогает, делает меня более уверенным. Попробуйте дать уникальные алиасы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 18:41 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorovNitro_Junkie, Ах... Вы используете одни и те же алиасы таблиц в разных частях запроса. Я не уверен, к какой `t0` привязывается планировщик в разных частях запроса: Код: 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. Тот факт, что `join_collapse_limit` помогает, делает меня более уверенным. Попробуйте дать уникальные алиасы. Там в планировщике она подчеркивания добавляет. Но честно попробовал, не помогло естественно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 18:44 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_JunkievyegorovПопробуйте дать уникальные алиасы. Там в планировщике она подчеркивания добавляет. Но честно попробовал, не помогло естественно. А можно увидеть измененный запрос и его планы, с обычными настройками и при `join_collaps_limit=2`? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.02.2015, 18:47 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorov, Запрос: Код: 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. Кривой план: Код: 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. Нормальный план (с join_collapse 2): Код: 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. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.02.2015, 09:44 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Интерсная картинка. При `jcl=2` планировщик увеличивает цену подзапросу `t1` и предпочитает HashJoin, что приводит к нужному эффекту. Почему так происходит понять не могу, в остальном планы одинаковые. Что возвращают такие запросы? Код: sql 1. 2. Вы можете смоделировать ситуацию на другой базе? Скажем, если дампнуть таблицы, создать новый кластер, загрузить таблицы, проанализировать их — какой будет план? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.02.2015, 12:19 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, оторвать бы кому-нибудь руки за такие имена таблиц и полей. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.02.2015, 12:20 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorov, "cpu_index_tuple_cost";"0.005";"default" "cpu_operator_cost";"0.0025";"default" "cpu_tuple_cost";"0.01";"default" "random_page_cost";"4";"default" "seq_page_cost";"1";"default" "application_name";"pgAdmin III - ???????????????????? ????????????????";"client" "bytea_output";"escape";"session" "client_encoding";"UNICODE";"session" "client_min_messages";"notice";"session" "DateStyle";"ISO, DMY";"session" "default_text_search_config";"pg_catalog.russian";"configuration file" "lc_messages";"Russian_Russia.1251";"configuration file" "lc_monetary";"Russian_Russia.1251";"configuration file" "lc_numeric";"Russian_Russia.1251";"configuration file" "lc_time";"Russian_Russia.1251";"configuration file" "listen_addresses";"*";"configuration file" "log_destination";"stderr";"configuration file" "log_line_prefix";"%t ";"configuration file" "log_timezone";"Europe/Bucharest";"configuration file" "logging_collector";"on";"configuration file" "max_connections";"100";"configuration file" "max_locks_per_transaction";"1000";"configuration file" "max_stack_depth";"2048";"environment variable" "port";"5432";"configuration file" "shared_buffers";"16384";"configuration file" "TimeZone";"Europe/Bucharest";"configuration file" "work_mem";"524288";"configuration file" Сча попробую dump restore. Но меня в принципе волнует вопрос почему при подсчете cost'а плана, СУБД не учитывает что при Nested Loop нужно несколько раз выполнять GroupAggregate. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.02.2015, 12:35 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Да, я понимаю про NestedLoops. Если вы сможете изолированно воспроизвести ситуацию, то можно написать разработчикам (я могу помочь). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.02.2015, 12:40 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorovNitro_Junkie, Да, я понимаю про NestedLoops. Если вы сможете изолированно воспроизвести ситуацию, то можно написать разработчикам (я могу помочь). Изолировать постараюсь в любом случае, и если он будет тривиальным запостить багрепорт, но пока мы прорабатываем вопрос решения проблемы в общем случае - самим материализовать подзапросы, если "что-то пошло не так". Можно конечно через CTE это делать, но там статистика плывет. Просто разработчики конечно может и помогут, но вряд ли они изменят, то что когда планировщик про Aggregate чего-то не знает, тупо лепит ему статистику 200, после чего начинаются чудеса с nested loop'ами. Плюс проблему надо решать уже :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.02.2015, 12:52 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_JunkieПлюс проблему надо решать уже :(А если добавить скобочки, чтобы явно задать порядок сортировки? Код: sql 1. 2. 3. 4. 5. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.02.2015, 15:33 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorovNitro_JunkieПлюс проблему надо решать уже :(А если добавить скобочки, чтобы явно задать порядок сортировки? Код: sql 1. 2. 3. 4. 5. Это уже похоже на перестановку кроватей. Тем более что явный порядок сортировки и задается уменьшением join_collapse_limit (как мы выяснили это как раз помогает). Вопрос почему она сама неправильно определяет порядок. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 09:27 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_JunkieЭто уже похоже на перестановку кроватей. Тем более что явный порядок сортировки и задается уменьшением join_collapse_limit (как мы выяснили это как раз помогает). Вопрос почему она сама неправильно определяет порядок. `join_collapse_limit` ограничивает планировщик в перестановке JOIN конструкций. В данном запросе эффект одинаковый (я полагаю?), однако может быть так, что уменьшение `join_collapse_limit` приведет к худшему плану. А скобочки позволяют точечно вправить мозг планировщику. Я согласен — почему “она сама неправильно определяет порядок” гораздо интереснее. Нужен тест кейс. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 10:17 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorov, В общем минимальное что смог пока найти: Код: 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. Код: 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. Второй внутренний подзапрос все не получается убрать. Соответственно проблема когда внутри LAST есть ORDER BY, если его убрать все становится хорошо: Код: 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. При этом что забавно агрегация идет в цикле. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 10:41 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Вообще конечно странно что во втором плане loops = 327 только в HashAggregate, а в первом идет вплоть до Index scan. При этом на самом деле разница только в том что в первом случае GroupAggregate с sort'ом, а во втором HashAggregate. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 10:51 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Собственно видимо в этом и проблем HashAggregate выполняется за 0,57 миллисекунды, а GroupAggregate за 122 миллисекунды. Хотя алгоритмическая сложность у них одинаковая и cost'ы тоже :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 10:54 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Собственно если сделать enable_sort TO off, который увеличит cost Group Aggregate до бесконечности все тоже становится ОК. Код: 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. Но не хочется включать enable_sort на весь сервер. :( ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 11:14 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Мне кажется, что планировщик неверно оценивает агрегатную функцию с `ORDER BY`. Поиграться бы с этим случаем. Вы какой-то дамп можете предоставить? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 11:30 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorovNitro_Junkie, Мне кажется, что планировщик неверно оценивает агрегатную функцию с `ORDER BY`. Поиграться бы с этим случаем. Вы какой-то дамп можете предоставить? Агрегатная функция в плане вообще не показывается. Может вы знаете где еще можно информацию достать. Но вообще что интересно у Hash Join в обоих планах и actual time и rows и cost одинаковые, но почему у HashAggregate, который идет строкой выше actual time 0.51, то есть деленное на loops, а у GroupAggregate нет - загадка. То есть я даже не могу догнать как именно он выполняет эти планы, не то что почему он их так оценивает. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 11:43 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, Агрегатная функция выражается в узлах `GroupAggregate` (который требует отсортированных данных) или `HashAggregate`, который быстрый и потому предпочтительней. Добавляя `ORDER BY` в агрегатную функцию вы задаете порядок, который требует сортировку. Ну и при таком раскладе можно использовать `GroupAgg`, т.к. данные уже отсортированы. Но планировщик (мне кажется) что-то не учитывает и запихивает `Sort`+`GroupAgg` в цикл, что выходит очень дорого. И вот этот момент хотелось бы прояснить у разработчиков. (От сортировки можно было бы избавиться через индекс, но у вас используются колонки из разных таблиц...) Общее время потраченное на узел считается как `actual time` * `loops`. Хотя на самом деле во время исполнения регистрируется общее время, а потом делиться на кол-во проходов. Тоже самое и для кол-ва реальных записей возвращенных узлом. Это иногда приводит к тому, что записи показывается как `0`, если некоторые проходы были безрезультатны. В случае с `HashAggregate` умножаем 0.483 на 327 и получаем 157ms, что похоже на общее время исполнения. Для `GroupAggregate` умножаем 122.150 (что уже почти равняется общему времени для `HashAgg`) на 327 и получаем 39943.05 (40 секунд). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 12:40 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorovNitro_Junkie, Агрегатная функция выражается в узлах `GroupAggregate` (который требует отсортированных данных) или `HashAggregate`, который быстрый и потому предпочтительней. Добавляя `ORDER BY` в агрегатную функцию вы задаете порядок, который требует сортировку. Ну и при таком раскладе можно использовать `GroupAgg`, т.к. данные уже отсортированы. Но планировщик (мне кажется) что-то не учитывает и запихивает `Sort`+`GroupAgg` в цикл, что выходит очень дорого. И вот этот момент хотелось бы прояснить у разработчиков. (От сортировки можно было бы избавиться через индекс, но у вас используются колонки из разных таблиц...) Общее время потраченное на узел считается как `actual time` * `loops`. Хотя на самом деле во время исполнения регистрируется общее время, а потом делиться на кол-во проходов. Тоже самое и для кол-ва реальных записей возвращенных узлом. Это иногда приводит к тому, что записи показывается как `0`, если некоторые проходы были безрезультатны. В случае с `HashAggregate` умножаем 0.483 на 327 и получаем 157ms, что похоже на общее время исполнения. Для `GroupAggregate` умножаем 122.150 (что уже почти равняется общему времени для `HashAgg`) на 327 и получаем 39943.05 (40 секунд). Попытался поиграться с планами, но в других случаях планировщик всегда вставляет, что-то типа следующего: [SQL] " -> Materialize (cost=6164744.96..6164838.15 rows=327 width=16) (actual time=80.627..80.630 rows=96 loops=327)" " -> Subquery Scan on t1 (cost=6164744.96..6164836.52 rows=327 width=16) (actual time=26364.901..26365.295 rows=96 loops=1)" " -> GroupAggregate (cost=6164744.96..6164833.25 rows=327 width=24) (actual time=26364.900..26365.286 rows=96 loops=1)" [/SQL] Почему он здесь этого не делает неясно. Более того я тогда вообще не понимаю пункта плана Materialize. Ведь в правильном исходном плане Materialize'а нет, но де-факто он происходит, как видим Hash Join идет 1 раз. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 13:07 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_Junkie, `Materialize` значит, что планировщик понимает, что одни и те же данные будут сканироваться некоторое число раз, и находит, что ему дешевле сохранить результат под-плана, а не вычислять его каждый раз заново. Естественно, такое возможно, если под-план всегда возвращает одинаковый результат. И я полагаю, что это стало возможным потому, что вы убрали функцию `ANYVALUE()` (как ранее указывал Максим). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 14:23 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorovNitro_Junkie, `Materialize` значит, что планировщик понимает, что одни и те же данные будут сканироваться некоторое число раз, и находит, что ему дешевле сохранить результат под-плана, а не вычислять его каждый раз заново. Естественно, такое возможно, если под-план всегда возвращает одинаковый результат. И я полагаю, что это стало возможным потому, что вы убрали функцию `ANYVALUE()` (как ранее указывал Максим). Тогда почему "в правильном исходном плане Materialize'а нет, но де-факто он происходит, как видим Hash Join идет 1 раз" ANYVALUE по моим наблюдениям никак не влияет на планы. Что он есть его нет... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 15:01 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
Nitro_JunkieТогда почему "в правильном исходном плане Materialize'а нет, но де-факто он происходит, как видим Hash Join идет 1 раз" Я не знаю. Предполагаю, что особенности работы с хэш-таблицей позволяют построить ее один раз (на основании результатов HashJoin) и затем просто возвращать агрегированные данные. Потому HashJoin loops=1, но вышестоящий HashAggregate loops=327. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.02.2015, 16:28 |
|
||
|
NESTED LOOP и GroupAggregate
|
|||
|---|---|---|---|
|
#18+
vyegorovNitro_JunkieТогда почему "в правильном исходном плане Materialize'а нет, но де-факто он происходит, как видим Hash Join идет 1 раз" Я не знаю. Предполагаю, что особенности работы с хэш-таблицей позволяют построить ее один раз (на основании результатов HashJoin) и затем просто возвращать агрегированные данные. Потому HashJoin loops=1, но вышестоящий HashAggregate loops=327. а для сортировки ее надо 327 раз джойнить? ммм ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.02.2015, 01:26 |
|
||
|
|

start [/forum/topic.php?all=1&fid=53&tid=1998148]: |
0ms |
get settings: |
5ms |
get forum list: |
14ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
168ms |
get topic data: |
9ms |
get forum data: |
2ms |
get page messages: |
87ms |
get tp. blocked users: |
2ms |
| others: | 238ms |
| total: | 529ms |

| 0 / 0 |
