Аль хэдийн хэрэглэж байгаа олон хүмүүс
... харгалзах төлөвлөгөөний зангилааны контекст зөвлөмж бүхий сайхан зохион бүтээсэн асуулга болгон:
Түүний хоёр дахь хэсгийн энэ хуулбар дээр
Асуулгын гүйцэтгэлийн ердийн асуудлууд, тэдгээрийн шийдлүүдэд зориулагдсан эхний хэсгийн хуулбарыг нийтлэлээс олж болно
"Эвдэрсэн SQL асуулгад зориулсан жор" .
Эхлээд будаж эхэлцгээе - мөн бид төлөвлөгөөг цаашид будахаа больсон, бид үүнийг аль хэдийн будсан, бидэнд аль хэдийн үзэсгэлэнтэй, ойлгомжтой, гэхдээ хүсэлт байна.
Ийм форматлагдаагүй "хуудас" -аас авсан хүсэлт нь маш муухай, тиймээс тохиромжгүй мэт санагдсан.
Ялангуяа хөгжүүлэгчид кодын хүсэлтийн хэсгийг нэг мөрөнд "наадаг" бол (энэ нь мэдээжийн хэрэг эсрэг загвар боловч ийм зүйл тохиолддог). Аймшигтай!
Үүнийг ямар нэгэн байдлаар илүү гоё зурцгаая.
Хэрэв бид үүнийг сайхан зурж чадвал, өөрөөр хэлбэл хүсэлтийн биеийг задалж, нэгтгэж чадвал төлөвлөгөөний холбогдох цэг дээр юу тохиолдсоныг энэ хүсэлтийн объект болгонд "хавсрах" боломжтой.
Асуулгын синтакс мод
Үүнийг хийхийн тулд эхлээд хүсэлтийг задлан шинжлэх ёстой.
Учир нь бидэнд байгаа
Бид хүсэлтийн хэсгийг функцийнхээ оролт болгон өгдөг - гаралт дээр бид JSON объект хэлбэрээр задлан шинжлэгдсэн синтакс модыг авдаг.
Одоо бид энэ модны дундуур эсрэг чиглэлд гүйж, хүссэн догол, өнгө, форматтай хүсэлтийг цуглуулж болно. Үгүй ээ, үүнийг өөрчлөх боломжгүй, гэхдээ энэ нь бидэнд тохиромжтой байх шиг санагдсан.
Зураглалын асуулга болон төлөвлөлтийн зангилаа
Одоо бид эхний алхамд дүн шинжилгээ хийсэн төлөвлөгөө, хоёрдугаарт дүн шинжилгээ хийсэн асуулгыг хэрхэн нэгтгэж болохыг харцгаая.
Энгийн жишээ авъя - бидэнд CTE үүсгэж, түүнээс хоёр удаа уншдаг асуулга байна. Тэр ийм төлөвлөгөө гаргадаг.
CTE
Хэрэв та үүнийг анхааралтай ажиглавал 12-р хувилбар хүртэл (эсвэл түлхүүр үгнээс эхлээд MATERIALIZED
) үүсэх
Энэ нь хэрэв бид хүсэлтийн хаа нэгтээ CTE генераци, төлөвлөгөөний хаа нэгтээ зангилаа байгааг харвал гэсэн үг юм CTE
, дараа нь эдгээр зангилаанууд хоорондоо "байлддаг" бол бид тэдгээрийг шууд нэгтгэж чадна.
Одтой холбоотой асуудал: CTE-г үүрлэх боломжтой.
Маш муу үүрлэсэн, тэр ч байтугай ижил нэртэй хүмүүс байдаг. Жишээлбэл, та дотор нь хийж болно 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
.
Дээрх "дээр" байгаа зүйл 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
.
Өгөгдөл унших-бичих
Бүх зүйл тодорхойлогдсон, одоо бид хүсэлтийн аль хэсэг нь төлөвлөгөөний аль хэсэгтэй тохирч байгааг мэдэж байна. Мөн эдгээр хэсгүүдээс бид "унших боломжтой" объектуудыг амархан бөгөөд байгалийн аргаар олж чадна.
Асуулгын үүднээс энэ нь хүснэгт эсвэл 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]
Бид төлөвлөгөөний бүтэц, асуулгын талаар мэддэг, блокуудын захидал харилцааг мэддэг, объектуудын нэрийг мэддэг - бид нэг нэгээр нь харьцуулалт хийдэг.
Дахин "одтой" даалгавар. Бид хүсэлтийг хүлээн авч, гүйцэтгэнэ, бидэнд өөр нэр байхгүй - бид үүнийг нэг CTE-ээс хоёр удаа уншсан.
Бид төлөвлөгөөг харж байна - ямар асуудал байна вэ? Бид яагаад өөр нэртэй болсон бэ? Бид захиалаагүй. Тэр хаанаас ийм “тооны дугаар” авдаг юм бэ?
PostgreSQL үүнийг өөрөө нэмдэг. Та үүнийг л ойлгох хэрэгтэй яг ийм хоч нэр Бидний хувьд төлөвлөгөөтэй харьцуулах үүднээс энэ нь ямар ч утгагүй, зүгээр л энд нэмсэн. Түүнд анхаарал хандуулахгүй байцгаая.
Хоёр дахь нь "одтой" даалгавар: хэрэв бид хуваасан хүснэгтээс уншиж байгаа бол зангилаа авах болно Append
буюу Merge Append
, энэ нь олон тооны "хүүхдүүд" -ээс бүрдэх бөгөөд тус бүр нь ямар нэгэн байдлаар байх болно Scan
Хүснэгтийн хэсгээс: Seq Scan
, Bitmap Heap Scan
буюу Index Scan
. Гэхдээ ямар ч тохиолдолд эдгээр "хүүхдүүд" нь нарийн төвөгтэй асуултууд биш байх болно - эдгээр зангилаанаас ийм байдлаар ялгах боломжтой. Append
at UNION
.
Бид бас ийм зангилаануудыг ойлгож, "нэг овоолго" цуглуулаад: "megatable-ээс уншсан бүх зүйл энд болон модны доор байна".
"Энгийн" өгөгдөл хүлээн авах цэгүүд
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
.
"Дугаарласан" дагавар нь тэдгээрийг бие биенээсээ ялгахад тусална - тэдгээрийг харгалзах дарааллаар нь нэмдэг. VALUES
-хүсэлтийн дагуу дээрээс доошоо блоклодог.
Өгөгдөл боловсруулах
Бидний хүсэлтийн бүх зүйл цэгцлэгдсэн юм шиг байна - үлдсэн зүйл Limit
.
Гэхдээ энд бүх зүйл энгийн байдаг - зангилаанууд Limit
, Sort
, Aggregate
, WindowAgg
, Unique
Хүсэлтэд байгаа холбогдох операторуудтай нэг нэгээр нь "газрын зураг" хийнэ үү. Энд ямар ч "од" эсвэл бэрхшээл байхгүй.
НЭГДЭХ
Бид нэгдэхийг хүсэх үед хүндрэл гардаг JOIN
өөр хоорондоо. Энэ нь үргэлж боломжтой байдаггүй, гэхдээ энэ нь боломжтой юм.
Асуулга задлагчийн үүднээс авч үзвэл бидэнд зангилаа байна JoinExpr
, яг хоёр хүүхэдтэй - зүүн ба баруун. Энэ нь таны НЭГДСЭН-ийн "дээд" болон хүсэлтэд "доор" гэж бичсэн зүйл юм.
Төлөвлөгөөний үүднээс авч үзвэл эдгээр нь зарим хүмүүсийн хоёр үр удам юм * Loop
/* Join
- зангилаа. Nested Loop
, Hash Anti Join
,... - тиймэрхүү нэг юм.
Энгийн логикийг ашиглацгаая: хэрвээ бидэнд төлөвлөгөөнд бие биенээ "нэгдсэн" А ба В хүснэгтүүд байгаа бол хүсэлтийн аль нэгийг нь байрлуулж болно. A-JOIN-B
, эсвэл B-JOIN-A
. Ингэж хослуулах гэж оролдъё, эсрэгээр нь хослуулах гэж оролдъё гэх мэтээр ийм хосууд дуусах хүртэл үргэлжилнэ.
Синтакс модоо авцгаая, төлөвлөгөөгөө авч үзье, тэдгээрийг харцгаая ... ижил төстэй биш!
Үүнийг график хэлбэрээр дахин зурцгаая - өө, энэ нь аль хэдийн ямар нэгэн зүйл шиг харагдаж байна!
Бидэнд нэгэн зэрэг B, C хүүхэдтэй зангилаа байдаг гэдгийг анхаарна уу - ямар дарааллаар бидэнд хамаагүй. Тэдгээрийг нэгтгэж, зангилааны зургийг эргүүлье.
Дахин харцгаая. Одоо бид А хүүхдүүдтэй зангилаанууд ба хосууд (B + C) байна - тэдэнтэй бас нийцдэг.
Агуу их! Бид энэ XNUMX юм байна лээ JOIN
хүсэлтээс төлөвлөгөөний зангилааг амжилттай хослуулсан.
Харамсалтай нь энэ асуудал үргэлж шийдэгддэггүй.
Жишээлбэл, хэрэв хүсэлт гаргасан бол A JOIN B JOIN C
, төлөвлөгөөнд юуны түрүүнд "гадна" зангилаа A ба C холбогдсон байна.Гэхдээ хүсэлтэд ийм оператор байхгүй, бидэнд онцлох зүйл байхгүй, сануулга хавсаргах зүйл алга. Бичиж байхдаа "таслал"-тай адилхан A, B
.
Гэхдээ ихэнх тохиолдолд бараг бүх зангилаануудыг "тайлж" болох бөгөөд та JavaScript кодыг шинжлэхдээ Google Chrome-д байгаа шиг цаг хугацааны хувьд зүүн талд ийм төрлийн профайлыг авах боломжтой. Мөр, мэдэгдэл тус бүрийг “гүйцэхэд” хэр хугацаа зарцуулсныг та харж болно.
Энэ бүхнийг ашиглахад илүү тохиромжтой болгохын тулд бид хадгалах сан хийсэн
Хэрэв та зүгээр л унших боломжгүй асуулгыг зохих хэлбэрт оруулах шаардлагатай бол ашиглана уу
Эх сурвалж: www.habr.com