PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Аль хэдийн хэрэглэж байгаа олон хүмүүс тайлбарлах.tensor.ru - Манай PostgreSQL төлөвлөгөөний дүрслэл үйлчилгээ нь түүний нэг гайхалтай давуу талыг мэдэхгүй байж магадгүй - серверийн бүртгэлийн уншихад хэцүү хэсгийг эргүүлэх...

PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ
... харгалзах төлөвлөгөөний зангилааны контекст зөвлөмж бүхий сайхан зохион бүтээсэн асуулга болгон:

PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ
Түүний хоёр дахь хэсгийн энэ хуулбар дээр PGConf.Russia 2020 дахь тайлан Бид яаж үүнийг хийж чадсаныг би танд хэлье.

Асуулгын гүйцэтгэлийн ердийн асуудлууд, тэдгээрийн шийдлүүдэд зориулагдсан эхний хэсгийн хуулбарыг нийтлэлээс олж болно "Эвдэрсэн SQL асуулгад зориулсан жор".



Эхлээд будаж эхэлцгээе - мөн бид төлөвлөгөөг цаашид будахаа больсон, бид үүнийг аль хэдийн будсан, бидэнд аль хэдийн үзэсгэлэнтэй, ойлгомжтой, гэхдээ хүсэлт байна.

Ийм форматлагдаагүй "хуудас" -аас авсан хүсэлт нь маш муухай, тиймээс тохиромжгүй мэт санагдсан.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Ялангуяа хөгжүүлэгчид кодын хүсэлтийн хэсгийг нэг мөрөнд "наадаг" бол (энэ нь мэдээжийн хэрэг эсрэг загвар боловч ийм зүйл тохиолддог). Аймшигтай!

Үүнийг ямар нэгэн байдлаар илүү гоё зурцгаая.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Хэрэв бид үүнийг сайхан зурж чадвал, өөрөөр хэлбэл хүсэлтийн биеийг задалж, нэгтгэж чадвал төлөвлөгөөний холбогдох цэг дээр юу тохиолдсоныг энэ хүсэлтийн объект болгонд "хавсрах" боломжтой.

Асуулгын синтакс мод

Үүнийг хийхийн тулд эхлээд хүсэлтийг задлан шинжлэх ёстой.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Учир нь бидэнд байгаа системийн цөм нь NodeJS дээр ажилладаг, дараа нь бид үүнд зориулж модуль хийсэн, та чадна GitHub дээрээс олоорой. Үнэн хэрэгтээ эдгээр нь PostgreSQL задлагчийн дотоод хэсгүүдэд өргөтгөсөн "холбогдол" юм. Өөрөөр хэлбэл, дүрэм нь ердөө л хоёртын системээр эмхэтгэсэн бөгөөд NodeJS-ээс түүнд холбоосууд хийгдсэн байдаг. Бид бусад хүмүүсийн модулийг үндэс болгон авсан - энд ямар ч том нууц байхгүй.

Бид хүсэлтийн хэсгийг функцийнхээ оролт болгон өгдөг - гаралт дээр бид JSON объект хэлбэрээр задлан шинжлэгдсэн синтакс модыг авдаг.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Одоо бид энэ модны дундуур эсрэг чиглэлд гүйж, хүссэн догол, өнгө, форматтай хүсэлтийг цуглуулж болно. Үгүй ээ, үүнийг өөрчлөх боломжгүй, гэхдээ энэ нь бидэнд тохиромжтой байх шиг санагдсан.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Зураглалын асуулга болон төлөвлөлтийн зангилаа

Одоо бид эхний алхамд дүн шинжилгээ хийсэн төлөвлөгөө, хоёрдугаарт дүн шинжилгээ хийсэн асуулгыг хэрхэн нэгтгэж болохыг харцгаая.

Энгийн жишээ авъя - бидэнд CTE үүсгэж, түүнээс хоёр удаа уншдаг асуулга байна. Тэр ийм төлөвлөгөө гаргадаг.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

CTE

Хэрэв та үүнийг анхааралтай ажиглавал 12-р хувилбар хүртэл (эсвэл түлхүүр үгнээс эхлээд MATERIALIZED) үүсэх CTE бол төлөвлөгчийн хувьд туйлын саад юм.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Энэ нь хэрэв бид хүсэлтийн хаа нэгтээ CTE генераци, төлөвлөгөөний хаа нэгтээ зангилаа байгааг харвал гэсэн үг юм CTE, дараа нь эдгээр зангилаанууд хоорондоо "байлддаг" бол бид тэдгээрийг шууд нэгтгэж чадна.

Одтой холбоотой асуудал: CTE-г үүрлэх боломжтой.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ
Маш муу үүрлэсэн, тэр ч байтугай ижил нэртэй хүмүүс байдаг. Жишээлбэл, та дотор нь хийж болно CTE A make CTE X, мөн дотор нь ижил түвшинд байна CTE B дахин хийх CTE X:

WITH A AS (
  WITH X AS (...)
  SELECT ...
)
, B AS (
  WITH X AS (...)
  SELECT ...
)
...

Харьцуулахдаа та үүнийг ойлгох хэрэгтэй. Үүнийг "нүдээрээ" ойлгох, тэр ч байтугай төлөвлөгөөг харах, хүсэлтийн үндсэн хэсгийг харах хүртэл маш хэцүү байдаг. Хэрэв таны CTE үе нь нарийн төвөгтэй, үүрлэсэн, хүсэлт нь том бол энэ нь бүрэн ухаангүй болно.

UNION

Хэрэв бид асуулгад түлхүүр үгтэй бол UNION [ALL] (хоёр дээжийг холбох оператор), дараа нь төлөвлөгөөнд энэ нь аль нэг зангилаатай тохирч байна Append, эсвэл зарим нь Recursive Union.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Дээрх "дээр" байгаа зүйл UNION - энэ бол "доор" байгаа манай зангилааны эхний удам юм - хоёр дахь нь. Хэрэв өнгөрвөл UNION Бид хэд хэдэн блокуудыг нэгэн зэрэг "наасан" Append-зөвхөн нэг зангилаа байх болно, гэхдээ энэ нь хоёр биш, харин олон хүүхэдтэй байх болно - дарааллаар нь:

  (...) -- #1
UNION ALL
  (...) -- #2
UNION ALL
  (...) -- #3

Append
  -> ... #1
  -> ... #2
  -> ... #3

Одтой холбоотой асуудал: доторх рекурсив түүвэр үүсгэх (WITH RECURSIVE) нэгээс олон байж болно UNION. Гэхдээ зөвхөн сүүлчийн блок нь үргэлж рекурсив байдаг UNION. Дээрх бүх зүйл нэг, гэхдээ өөр UNION:

WITH RECURSIVE T AS(
  (...) -- #1
UNION ALL
  (...) -- #2, тут кончается генерация стартового состояния рекурсии
UNION ALL
  (...) -- #3, только этот блок рекурсивный и может содержать обращение к T
)
...

Та мөн ийм жишээнүүдийг "нацаж" чаддаг байх хэрэгтэй. Энэ жишээн дээр бид үүнийг харж байна UNION-Бидний хүсэлтэд 3 хэсэг байсан. Үүний дагуу нэг UNION харгалзана Append-зангилаа, нөгөө рүү - Recursive Union.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Өгөгдөл унших-бичих

Бүх зүйл тодорхойлогдсон, одоо бид хүсэлтийн аль хэсэг нь төлөвлөгөөний аль хэсэгтэй тохирч байгааг мэдэж байна. Мөн эдгээр хэсгүүдээс бид "унших боломжтой" объектуудыг амархан бөгөөд байгалийн аргаар олж чадна.

Асуулгын үүднээс энэ нь хүснэгт эсвэл CTE эсэхийг бид мэдэхгүй, гэхдээ тэдгээр нь ижил зангилаагаар тодорхойлогддог. RangeVar. Мөн "унших чадвар" -ын хувьд энэ нь нэлээд хязгаарлагдмал зангилаа юм:

  • Seq Scan on [tbl]
  • Bitmap Heap Scan on [tbl]
  • Index [Only] Scan [Backward] using [idx] on [tbl]
  • CTE Scan on [cte]
  • Insert/Update/Delete on [tbl]

Бид төлөвлөгөөний бүтэц, асуулгын талаар мэддэг, блокуудын захидал харилцааг мэддэг, объектуудын нэрийг мэддэг - бид нэг нэгээр нь харьцуулалт хийдэг.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Дахин "одтой" даалгавар. Бид хүсэлтийг хүлээн авч, гүйцэтгэнэ, бидэнд өөр нэр байхгүй - бид үүнийг нэг CTE-ээс хоёр удаа уншсан.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Бид төлөвлөгөөг харж байна - ямар асуудал байна вэ? Бид яагаад өөр нэртэй болсон бэ? Бид захиалаагүй. Тэр хаанаас ийм “тооны дугаар” авдаг юм бэ?

PostgreSQL үүнийг өөрөө нэмдэг. Та үүнийг л ойлгох хэрэгтэй яг ийм хоч нэр Бидний хувьд төлөвлөгөөтэй харьцуулах үүднээс энэ нь ямар ч утгагүй, зүгээр л энд нэмсэн. Түүнд анхаарал хандуулахгүй байцгаая.

Хоёр дахь нь "одтой" даалгавар: хэрэв бид хуваасан хүснэгтээс уншиж байгаа бол зангилаа авах болно Append буюу Merge Append, энэ нь олон тооны "хүүхдүүд" -ээс бүрдэх бөгөөд тус бүр нь ямар нэгэн байдлаар байх болно ScanХүснэгтийн хэсгээс: Seq Scan, Bitmap Heap Scan буюу Index Scan. Гэхдээ ямар ч тохиолдолд эдгээр "хүүхдүүд" нь нарийн төвөгтэй асуултууд биш байх болно - эдгээр зангилаанаас ийм байдлаар ялгах боломжтой. Append at UNION.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Бид бас ийм зангилаануудыг ойлгож, "нэг овоолго" цуглуулаад: "megatable-ээс уншсан бүх зүйл энд болон модны доор байна".

"Энгийн" өгөгдөл хүлээн авах цэгүүд

PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Values Scan төлөвлөгөөнд нийцэж байна VALUES хүсэлтэд.

Result байхгүй хүсэлт юм FROM шиг SELECT 1. Эсвэл та санаатайгаар худал илэрхийлсэн үед WHERE-блок (дараа нь атрибут гарч ирнэ One-Time Filter):

EXPLAIN ANALYZE
SELECT * FROM pg_class WHERE FALSE; -- или 0 = 1

Result  (cost=0.00..0.00 rows=0 width=230) (actual time=0.000..0.000 rows=0 loops=1)
  One-Time Filter: false

Function Scan ижил нэртэй SRF-ийн "газрын зураг".

Гэхдээ үүрлэсэн асуулгад бүх зүйл илүү төвөгтэй байдаг - харамсалтай нь тэд үргэлж болж хувирдаггүй InitPlan/SubPlan. Заримдаа тэд болж хувирдаг ... Join буюу ... Anti Join, ялангуяа та ийм зүйл бичих үед WHERE NOT EXISTS .... Энд тэдгээрийг нэгтгэх нь үргэлж боломжгүй байдаг - төлөвлөгөөний текстэнд төлөвлөгөөний зангилаатай тохирох операторууд байдаггүй.

Дахин "одтой" даалгавар: зарим VALUES хүсэлтэд. Энэ тохиолдолд болон төлөвлөгөөнд та хэд хэдэн зангилаа авах болно Values Scan.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

"Дугаарласан" дагавар нь тэдгээрийг бие биенээсээ ялгахад тусална - тэдгээрийг харгалзах дарааллаар нь нэмдэг. VALUES-хүсэлтийн дагуу дээрээс доошоо блоклодог.

Өгөгдөл боловсруулах

Бидний хүсэлтийн бүх зүйл цэгцлэгдсэн юм шиг байна - үлдсэн зүйл Limit.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Гэхдээ энд бүх зүйл энгийн байдаг - зангилаанууд Limit, Sort, Aggregate, WindowAgg, Unique Хүсэлтэд байгаа холбогдох операторуудтай нэг нэгээр нь "газрын зураг" хийнэ үү. Энд ямар ч "од" эсвэл бэрхшээл байхгүй.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

НЭГДЭХ

Бид нэгдэхийг хүсэх үед хүндрэл гардаг JOIN өөр хоорондоо. Энэ нь үргэлж боломжтой байдаггүй, гэхдээ энэ нь боломжтой юм.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Асуулга задлагчийн үүднээс авч үзвэл бидэнд зангилаа байна JoinExpr, яг хоёр хүүхэдтэй - зүүн ба баруун. Энэ нь таны НЭГДСЭН-ийн "дээд" болон хүсэлтэд "доор" гэж бичсэн зүйл юм.

Төлөвлөгөөний үүднээс авч үзвэл эдгээр нь зарим хүмүүсийн хоёр үр удам юм * Loop/* Join- зангилаа. Nested Loop, Hash Anti Join,... - тиймэрхүү нэг юм.

Энгийн логикийг ашиглацгаая: хэрвээ бидэнд төлөвлөгөөнд бие биенээ "нэгдсэн" А ба В хүснэгтүүд байгаа бол хүсэлтийн аль нэгийг нь байрлуулж болно. A-JOIN-B, эсвэл B-JOIN-A. Ингэж хослуулах гэж оролдъё, эсрэгээр нь хослуулах гэж оролдъё гэх мэтээр ийм хосууд дуусах хүртэл үргэлжилнэ.

Синтакс модоо авцгаая, төлөвлөгөөгөө авч үзье, тэдгээрийг харцгаая ... ижил төстэй биш!
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Үүнийг график хэлбэрээр дахин зурцгаая - өө, энэ нь аль хэдийн ямар нэгэн зүйл шиг харагдаж байна!
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Бидэнд нэгэн зэрэг B, C хүүхэдтэй зангилаа байдаг гэдгийг анхаарна уу - ямар дарааллаар бидэнд хамаагүй. Тэдгээрийг нэгтгэж, зангилааны зургийг эргүүлье.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Дахин харцгаая. Одоо бид А хүүхдүүдтэй зангилаанууд ба хосууд (B + C) байна - тэдэнтэй бас нийцдэг.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Агуу их! Бид энэ XNUMX юм байна лээ JOIN хүсэлтээс төлөвлөгөөний зангилааг амжилттай хослуулсан.

Харамсалтай нь энэ асуудал үргэлж шийдэгддэггүй.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Жишээлбэл, хэрэв хүсэлт гаргасан бол A JOIN B JOIN C, төлөвлөгөөнд юуны түрүүнд "гадна" зангилаа A ба C холбогдсон байна.Гэхдээ хүсэлтэд ийм оператор байхгүй, бидэнд онцлох зүйл байхгүй, сануулга хавсаргах зүйл алга. Бичиж байхдаа "таслал"-тай адилхан A, B.

Гэхдээ ихэнх тохиолдолд бараг бүх зангилаануудыг "тайлж" болох бөгөөд та JavaScript кодыг шинжлэхдээ Google Chrome-д байгаа шиг цаг хугацааны хувьд зүүн талд ийм төрлийн профайлыг авах боломжтой. Мөр, мэдэгдэл тус бүрийг “гүйцэхэд” хэр хугацаа зарцуулсныг та харж болно.
PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Энэ бүхнийг ашиглахад илүү тохиромжтой болгохын тулд бид хадгалах сан хийсэн архив, эндээс та төлөвлөгөөгөө хадгалах, дараа нь холбогдох хүсэлтийн хамт олох эсвэл холбоосыг хэн нэгэнтэй хуваалцах боломжтой.

Хэрэв та зүгээр л унших боломжгүй асуулгыг зохих хэлбэрт оруулах шаардлагатай бол ашиглана уу Манай "хэвийн тохируулагч".

PostgreSQL Query Profiler: төлөвлөгөө болон асуулга хэрхэн тааруулах вэ

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх