Ачааллж байна...
Сүүлийн хэдэн бүлгийн турш бид хэд хэдэн асуултыг "дараа шийднэ" гэж хойшлуулсаар ирсэн. Бүлэг 5-д Батын сургалтуудыг олохын тулд эхний query-ний үр дүнг (1, 2, 3) гараар хуулж, хоёр дахь query-ний IN жагсаалтад буулгасан. Бүлэг 8-ын эхний хичээлд "дундаж хувиас олон хувьтай номнууд"-ыг олох гэж WHERE copies > AVG(copies) бичихэд misuse of aggregate гэсэн алдаа гарсан. Өмнөх хичээлийн жанрын тайланд мөр үржилт SUM-ийг худал болгосон бөгөөд DISTINCT түүнийг засаж чадаагүй. Мөн Бүлэг 2-ын NULL-ийн хичээлд "жагсаалтыг өөр query-ээс автоматаар авах үед NULL чимээгүйхэн орж ирж бүхэл тайлан хоосон гарч болно" гэж анхааруулсан.
Эдгээр бүх асуудлын шийдэл нэг: query-ний дотор өөр нэг query бичих. Үүнийг subquery гэдэг. Subquery нь хаалт дотор бичигдэх бүрэн SELECT бөгөөд түүний үр дүн гаднах query-ний нэг хэсэг болж ажилладаг — ганц утга, утгын жагсаалт, эсвэл бүтэн хүснэгт хэлбэрээр. Бичлэгийн хувьд та юу ч шинээр сурах шаардлагагүй: дотор нь бичигдэх query нь таны мэдэх SELECT л юм.
Энэ хичээлд subquery-ийн гурван хэлбэрийг харж, хойшлуулсан асуудал бүрийг шийднэ. Мөн шударга нэг асуултад хариулна: subquery ба JOIN олон тохиолдолд ижил асуултад хариулж чаддаг — аль нь хэзээ уншихад илүү ойлгомжтой вэ? Энэ асуултад догмагүй, практик зөвлөгөө өгнө. library2.db-г нээгээрэй — бид зөвхөн уншина.
Эрхлэгч номын санчид даалгавар өгөхдөө заримдаа хоёр шаттай заавар өгдөг: "Эхлээд энэ сарын дундаж зээлийн тоог тооцоол. Дараа нь тэр дунджаас олон зээлсэн гишүүдийн жагсаалтыг гарга." Номын санч эхний шатыг дуусгаад цаасан дээр нэг тоо бичнэ — тэгээд тэр тоог хоёр дахь шатанд ашиглана. Эхний шатны үр дүн хоёр дахь шатны материал болдог.
Subquery бол яг ийм дотоод шат юм. Гаднах query бол эрхлэгчийн гол асуулт, хаалт доторх query бол түүнд хариулахын тулд эхлээд хийх тусламжийн тооцоо. Бүлэг 5-д бид энэ хоёр шатыг гараар — эхний query-ний үр дүнг хуулж — холбосон. Subquery нь тэр хуулах ажлыг өгөгдлийн санд даатгадаг: дотоод query-ний үр дүн автоматаар гаднах query руу дамжина.
Бүлэг 8-ын эхний хичээлийн асуулт: дундаж хувиас олон хувьтай номнууд аль нь вэ? Тэнд WHERE copies > AVG(copies) алдаа өгсөн, учир нь WHERE мөр бүрийг дангаар нь шалгадаг бөгөөд тэр мөчид дундаж тооцоологдоогүй байдаг. Subquery нь дунджийг тусад нь, урьдчилан тооцоолох боломж олгодог. Query:
sql
SELECT title, copies
FROM books
WHERE copies > (SELECT AVG(copies) FROM books)
ORDER BY copies DESC;Үр дүн:
title | copies
--------------------+-------
Python Crash Course | 5
Clean Code | 4
Тунгалаг Тамир | 3Энэ query юу гэж хэлж байна вэ гэвэл: "эхлээд books-ийн хувийн дунджийг тооцоол; дараа нь books-ээс хувь нь тэр дунджаас их номнуудын нэр ба хувийг хувиар ихээс бага руу эрэмбэлж харуул."
Хоёр шатаар мөшгье. Дотоод query SELECT AVG(copies) FROM books нь Бүлэг 8-ын эхний хичээлд тооцоолсон 2.5-ыг буцаана — нэг мөр, нэг багана, нэг утга. Гаднах query-ний WHERE одоо copies > 2.5 гэж ажиллаж байгаатай адил: мөр бүрийг энгийн тоотой харьцуулна. Найман номоос хувь нь 2.5-аас их гурав нь үлдэнэ. Ийм ганц утга буцаадаг subquery-г scalar subquery гэдэг — “scalar” нь "ганц утга" гэсэн утгатай. Scalar subquery нь аливаа тоо эсвэл текст бичиж болох газар бүрт бичигдэж болно.
Энэ query-ний хамгийн чухал давуу тал нь 2.5 гэдэг тоог бид хаана ч бичээгүйд оршино. Хэрэв маргааш номын санд арван хувьтай шинэ ном ирвэл дундаж өөрчлөгдөж, энэ query өөрчлөлтгүйгээр шинэ үнэн хариу өгнө. Хэрэв бид 2.5-ыг гараар бичсэн бол тэр тоо Бүлэг 6-ийн Дулмаагийн тоолуур шиг хуучирч, худал болох байсан.
Жишээ 1: scalar subquery SELECT-д
Scalar subquery зөвхөн WHERE-д биш, SELECT-д ч бичигдэж болно. Ном бүрийн хувийг дундажтай зэрэгцүүлж харъя:
sql
SELECT title,
copies,
(SELECT AVG(copies) FROM books) AS avg_copies,
copies - (SELECT AVG(copies) FROM books) AS diff
FROM books
ORDER BY diff DESC;Үр дүн:
title | copies | avg_copies | diff
-------------------------+--------+------------+-----
Python Crash Course | 5 | 2.5 | 2.5
Clean Code | 4 | 2.5 | 1.5
Тунгалаг Тамир | 3 | 2.5 | 0.5
Монголын нууц товчоо | 2 | 2.5 | -0.5
The Pragmatic Programmer | 2 | 2.5 | -0.5
Миний нутаг | 2 | 2.5 | -0.5
Учиртай гурван толгой | 1 | 2.5 | -1.5
Clean Architecture | 1 | 2.5 | -1.5Энэ query юу гэж хэлж байна вэ гэвэл: “books-ийн мөр бүрийн хувьд номын нэр, хувь, бүх номын хувийн дундаж, мөн хувь ба дунджийн зөрүүг зөрүүгээр ихээс бага руу эрэмбэлж харуул.” Бүлэг 8-ын эхний хичээлийн төгсгөлд “aggregate-тэй query-ний SELECT-д энгийн багана бүү холь” гэж сурсан. Энд бид яг тэгж хийсэн мэт харагдаж байна — title болон AVG(copies) нэг мөрөнд. Ялгаа нь AVG нь тусдаа query-д, өөрийн бүх мөр дээр ажиллаж байна; гаднах query aggregate-гүй, найман мөр бүрийг тусад нь харуулж байна. Subquery-ийн үр дүн мөр бүрт ижил тоо болж залгагдсан. Ийнхүү subquery нь "нэг мөрийн утга" ба "бүх мөрийн нийлбэр"-ийг нэг үр дүнд зэрэгцүүлэх цэвэр арга юм.
Жишээ 2: IN (SELECT ...) — жагсаалт буцаадаг subquery
Бүлэг 5-ын гар ажил руу буцъя. Одоо гарт ном байгаа гишүүд хэн бэ? Query:
sql
SELECT name, email
FROM members
WHERE id IN (SELECT member_id FROM loans WHERE returned_on IS NULL)
ORDER BY name;Үр дүн:
name | email
---------+------------------
Бат | bat@example.com
Сараа | saraa@example.com
Тэмүүлэн | NULLЭнэ query юу гэж хэлж байна вэ гэвэл: "эхлээд буцаагаагүй зээлүүдийн гишүүний дугааруудыг ол; дараа нь members-ээс id нь тэр жагсаалтад байгаа гишүүдийн нэр ба имэйлийг нэрээр эрэмбэлж харуул." Дотоод query гурван дугаар буцаана: 1, 2, 3. Гаднах query WHERE id IN (1, 2, 3) шиг ажиллана — Бүлэг 2-ын IN хичээлийн хэрэгсэл, гэхдээ жагсаалтыг одоо гараар биш, query бичиж байна. Бүлэг 5-д бид яг энэ хуулах ажлыг гараар хийж, "Бүлэг 9-д эхний query-г хоёр дахин дотор нь шууд байрлуулах аргыг сурна" гэж хэлсэн.
Энэ асуултыг Бүлэг 7-ийн INNER JOIN-оор ч шийдэж болно: SELECT m.name, m.email FROM members AS m INNER JOIN loans AS l ON l.member_id = m.id WHERE l.returned_on IS NULL. Одоогоор үр дүн ижил. Гэвч хэрэв Бат хоёр ном гартаа байлгадаг байсан бол JOIN түүнийг хоёр мөрөөр харуулах байсан (Бүлэг 7-ийн мөр үржилт) — DISTINCT нэмэх хэрэгтэй болно. IN нь "энэ гишүүн жагсаалтад байна уу" гэж л асуудаг тул хэдэн удаа байгаагаас үл хамааран гишүүн нэг л удаа гарна. Энэ нь доор ярих "хэзээ аль нь" гэсэн зөвлөгөөний эхний түлхүүр.
Жишээ 3: NOT IN ба NULL-ийн урхи — Бүлэг 2-ын амлалт
Хэзээ ч ном зээлээгүй гишүүдийг subquery-ээр олъё. Query:
sql
SELECT name
FROM members
WHERE id NOT IN (SELECT member_id FROM loans);Үр дүн:
name
----
АнуЭнэ query юу гэж хэлж байна вэ гэвэл: “members-ээс id нь зээлийн хүснэгтэд гарсан гишүүний дугааруудын жагсаалтад ороогүй гишүүдийн нэрийг харуул.” Зөв, найдвартай — учир нь loans.member_id нь NOT NULL тул дотоод жагсаалтад NULL байх боломжгүй.
Одоо Бүлэг 2-т анхааруулсан урхийг бодитоор харъя. Зохиогчийн холбоосгүй номнуудыг олох гэж байна. Хэн нэгэн дотоод query-г бичихдээ "зохиогчтой холбогдсон бүх номын дугаарыг" авахын тулд authors-ээс эхэлж LEFT JOIN хийжээ:
sql
SELECT title
FROM books
WHERE id NOT IN (
SELECT ba.book_id
FROM authors AS a
LEFT JOIN book_authors AS ba ON ba.author_id = a.id
);Үр дүн:
(хоосон — 0 мөр)Энэ query юу гэж хэлж байна вэ гэвэл: "бүх зохиогчийг холбоосуудтай нь (холбоосгүйг нь ч хадгалан) нийлүүлж, номын дугааруудыг ав; дараа нь books-ээс id нь тэр жагсаалтад ороогүй номнуудыг харуул." "Монголын нууц товчоо" зохиогчийн холбоосгүй тул гарч ирэх ёстой байсан — гэвч хоосон. Яагаад? Дотоод query-г дангаар нь ажиллуулбал шалтгаан харагдана: 2, 3, 4, 5, 6, 6, 7, 8 — мөн NULL. Al Sweigart номгүй тул LEFT JOIN түүний мөрийг хадгалж, book_id-г NULL болгосон. Бүлэг 2-т сурсанчлан NOT IN-ий жагсаалтад ганц NULL орвол "энэ утга NULL-ээс ялгаатай юу" гэдэг нь "мэдэхгүй" болж, ямар ч мөр нэвтрэхгүй.
Энэ бол бодит, түгээмэл алдаа: дотоод query-ний LEFT JOIN-ыг хэн нэгэн өөр зорилгоор нэмсэн, NOT IN-ий бичсэн хүн тэр жагсаалтад NULL орж ирснийг мэдээгүй. Засах гурван арга бий. Нэгдүгээрт, дотоод query-д NULL-ийг ил тод хасах: WHERE ba.book_id IS NOT NULL. Хоёрдугаарт, Бүлэг 7-ийн LEFT JOIN ... WHERE ... IS NULL загварыг ашиглах. Гуравдугаарт, NOT EXISTS ашиглах — үүнийг дараагийн жишээнд харна. Практик дүрэм: NOT IN-ийг зөвхөн дотоод query нь NULL буцаах боломжгүй гэдэгт итгэлтэй үед л ашигла.
Жишээ 4: EXISTS ба холбоотой subquery
Одоог хүртэлх subquery-нүүд бүгд бие даасан байсан — гаднах query-гээс үл хамааран нэг удаа ажиллаж, үр дүнгээ өгдөг. Өөр төрлийн subquery бий: гаднах query-ний мөр бүрт тусад нь ажилладаг, тэр мөрийн утгыг дотроо ашигладаг. Үүнийг холбоотой subquery (correlated subquery) гэдэг. Хэзээ ч зээлээгүй гишүүдийг ийм аргаар олъё:
sql
SELECT m.name
FROM members AS m
WHERE NOT EXISTS (
SELECT 1
FROM loans AS l
WHERE l.member_id = m.id
);Үр дүн:
name
----
АнуЭнэ query юу гэж хэлж байна вэ гэвэл: “members-ийн гишүүн бүрийн хувьд, loans хүснэгтэд түүний id-тай зээл байхгүй бол нэрийг нь харуул.” Дотоод query-ний WHERE m.id-г ашиглаж байгааг анзаараарай — m бол гаднах query-ний хүснэгт. Энэ нь дотоод query-г "гишүүн бүрт тусад нь" болгож байна: Батын хувьд l.member_id = 1, Сараагийн хувьд = 2 гэх мэт. EXISTS нь "энэ дотоод query дор хаяж нэг мөр буцаах уу" гэж асуудаг бөгөөд NOT EXISTS эсрэгээр нь. SELECT 1 нь утгагүй мэт харагдана — EXISTS-д баганын агуулга хамаагүй, зөвхөн мөр байгаа эсэх л чухал тул уламжлал болгон 1 бичдэг.
NOT EXISTS-ийн гол давуу тал нь Жишээ 3-ын урхинаас ангид байдал. Энэ нь утгуудыг жагсаалттай харьцуулдаггүй, зөвхөн "тохирох мөр байна уу" гэж асуудаг тул NULL түүнийг хордуулж чадахгүй. "Бусад хүснэгтэд байхгүй" гэсэн асуултад NOT EXISTS ба Бүлэг 7-ийн LEFT JOIN загвар хоёулаа найдвартай; NOT IN нь нөхцөлтэйгээр найдвартай.
Холбоотой subquery-г SELECT-д ч бичиж болно: SELECT title, (SELECT COUNT(*) FROM loans AS l WHERE l.book_id = b.id) AS times_loaned FROM books AS b; нь ном бүрийн зээлийн тоог (зээлгүй номд 0) буцаана — Бүлэг 8-ын LEFT JOIN ба GROUP BY-ийн ажлыг өөр аргаар хийж байна. Энэ нь уншихад маш ойлгомжтой ч дотоод query мөр бүрт ажилладаг тул маш том хүснэгт дээр удаан байж болно. Дараагийн хичээлийн index энэ асуудлыг ихээхэн багасгадаг.
Жишээ 5: FROM дахь subquery — мөр үржилтийг шийдэх
Одоо өмнөх хичээлийн Тайлан 4-ийн урхи руу буцъя. Жанр бүрийн номын тоо, хувийн нийлбэр, зээлийн тоог нэг тайланд гаргах гэхэд books-ийг loans-тай JOIN хийснээс болж хувийн нийлбэр үржиж (програмчлал 12-ын оронд 20) байсан. Асуудлын үндэс: хоёр өөр нийлбэрийг — номын ба зээлийн — нэг JOIN-ий мөрүүд дээр бодсон. Шийдэл: нийлбэр бүрийг тусдаа query-д, JOIN-оос өмнө бодоод, дараа нь бэлэн нийлбэрүүдийг нийлүүлэх. Subquery нь FROM-д бичигдэж, түр зуурын хүснэгт шиг ажиллаж чадна. Query:
sql
SELECT bc.genre,
bc.book_count,
bc.total_copies,
COALESCE(lc.times_loaned, 0) AS times_loaned
FROM (
SELECT genre, COUNT(*) AS book_count, SUM(copies) AS total_copies
FROM books
GROUP BY genre
) AS bc
LEFT JOIN (
SELECT b.genre, COUNT(*) AS times_loaned
FROM loans AS l
INNER JOIN books AS b ON l.book_id = b.id
GROUP BY b.genre
) AS lc ON lc.genre = bc.genre
ORDER BY bc.genre;Үр дүн:
genre | book_count | total_copies | times_loaned
------------+------------+--------------+-------------
Жүжиг | 1 | 1 | 0
Програмчлал | 4 | 12 | 5
Роман | 1 | 3 | 2
Түүх | 1 | 2 | 0
Шүлэг | 1 | 2 | 1Энэ query юу гэж хэлж байна вэ гэвэл: "эхлээд books-ийг жанраар сагсалж жанр бүрийн номын тоо ба хувийн нийлбэрийг тооцоолоод bc гэж нэрлэ; дараа нь зээлүүдийг номтой нийлүүлж жанраар сагсалж жанр бүрийн зээлийн тоог тооцоолоод lc гэж нэрлэ; эцэст нь bc-ийн бүх жанрыг (зээлгүйг нь ч хадгалан) lc-тэй жанраар нийлүүлж, зээлгүй жанрын хоосон тоог 0 болгон харуул."
Хувийн нийлбэр одоо зөв: програмчлал 12, роман 3 — Бүлэг 8-ын GROUP BY хичээлийн Жишээ 3-тай таарч байна. Учир нь bc subquery зөвхөн books-ийг харж, ном бүрийг нэг л удаа тоолсон — зээлүүд түүнд хүрээгүй. lc subquery зөвхөн зээлүүдийг тоолсон. Хоёр нийлбэр тус тусдаа, үржилтгүйгээр бодогдож, дараа нь жанр бүрт яг нэг мөртэй хоёр "түр хүснэгт" нийлсэн — нэг-нэг харилцаа тул JOIN ямар ч мөр үржүүлэхгүй. COALESCE нь Бүлэг 8-ын эхний хичээлд сурсан хэрэгсэл: LEFT JOIN-оос ирсэн NULL-ийг 0 болгоно.
FROM дахь subquery-д AS-ээр нэр (bc, lc) өгсөн нь заавал хэрэгтэй — гаднах query тэр нэрээр түүний баганыг дууддаг. Энэ хэлбэрийг "урьдчилан нэгтгээд, дараа нь нийлүүл" гэж санаж болно: мөр үржилт гарч болох бүх тайланд энэ бол стандарт засвар.
Энэ хичээлийн хэд хэдэн жишээ Бүлэг 7, 8-ын JOIN-оор ч шийдэгдэж болох байсан. Тэгвэл аль нь зөв бэ? Шударга хариулт: ихэнх тохиолдолд хоёулаа зөв, өгөгдлийн сангууд олонхдоо тэднийг ижил хурдаар гүйцэтгэдэг. Сонголт нь гол төлөв уншихад аль нь илүү ойлгомжтойгоос хамаарна. Хэдэн практик дүрэм:
Нөгөө хүснэгтийн баганыг үр дүнд харуулах шаардлагатай бол — JOIN. Зээлийн тайланд номын нэр, гишүүний нэр хоёулаа хэрэгтэй бол JOIN л байгалийн сонголт. IN нь зөвхөн шүүдэг, баганыг дамжуулдаггүй.
Зөвхөн "холбоотой зүйл байгаа эсэх"-ээр шүүх бол — IN эсвэл EXISTS. Жишээ 2 шиг, JOIN-ий мөр үржилт ба DISTINCT-ийн санаа зоволтгүйгээр.
"Байхгүй" гэсэн шүүлт бол — NOT EXISTS эсвэл LEFT JOIN ... IS NULL. NOT IN-ийг зөвхөн дотоод query NULL буцаахгүй гэдэгт итгэлтэй үед.
Нийлбэртэй харьцуулах бол — scalar subquery. "Дунджаас их" гэх мэт асуултад subquery бол цорын ганц цэвэр арга.
Хоёр өөр нийлбэрийг нэг тайланд — FROM дахь subquery. Мөр үржилтийг "урьдчилан нэгтгээд, дараа нь нийлүүл" аргаар шийднэ.
Мөн анхааруулга: subquery-г subquery дотор, тэрийг нь дахин subquery дотор бичиж болох ч гурав, дөрвөн давхар үүрлэсэн query-г уншиж ойлгох нь маш хэцүү болдог. Хэрэв query тань ийм болж байвал PostgreSQL-ийн CTE (WITH гэсэн бичлэг) гэх мэт илүү уншигдахуйц хэрэгслийг ашиглах цаг болсон гэсэн дохио — энэ сургалтын төгсгөлд тэдгээрийг дараагийн алхам болгон нэрлэнэ.
Хэрэв сонирхож байвал хамгийн их зээлэгдсэн номын нэрийг scalar subquery-ээр олж үзээрэй: эхлээд дотоод query-ээр зээлийн хамгийн их тоог олоод, гаднах query-д тэр тооноос их буюу тэнцүү зээлтэй номыг ол — тэнцсэн хоёр ном байвал хоёулаа гарах давуу талтай (LIMIT 1-ээс ялгаатай нь). Мөн Жишээ 3-ын урхит query-ний дотоод хэсгийг дангаар нь ажиллуулж NULL-ийг өөрийн нүдээр хараад, гурван засварын аль нэгийг нь хэрэглэж үзээрэй. Эдгээр нь зөвхөн санал бөгөөд дараагийн хичээлүүд тэдгээрийг хийсэн гэж тооцохгүй.
Subquery-ийн хаалтыг мартах. WHERE copies > SELECT AVG(copies) FROM books гэж хаалтгүй бичвэл near "SELECT": syntax error гарна. Энэ мессеж юу гэж хэлж байна вэ гэвэл: “SELECT гэдэг үгийн ойролцоо SQL-ийн дүрэм зөрчигдлөө.” Subquery үргэлж хаалтанд бичигдэнэ.
Scalar subquery олон мөр буцаах. Ганц утга хүлээж байгаа газарт олон мөр буцаадаг subquery бичвэл — жишээ нь WHERE copies > (SELECT copies FROM books WHERE genre = 'Програмчлал') — SQLite алдаа өгөхгүй, зүгээр л эхний мөрийн утгыг ашиглана. Үр дүн нь дурын мэт харагдана. PostgreSQL харин more than one row returned by a subquery used as an expression гэсэн алдаа өгнө — "илэрхийлэл болгон ашигласан subquery нэгээс олон мөр буцаалаа." Scalar subquery-ийг дангаар нь ажиллуулж нэг мөр буцааж байгааг шалгаарай; олон утгатай харьцуулах бол IN эсвэл aggregate (MAX, AVG) хэрэглэ.
NOT IN-ий жагсаалтад NULL. Жишээ 3-т харсанчлан алдааны мессежгүй хоосон үр дүн. NOT IN-тэй query хоосон гарвал дотоод query-г дангаар нь ажиллуулж NULL байгаа эсэхийг хараарай.
FROM дахь subquery-д нэр өгөхгүй байх. SQLite нэргүй subquery-г FROM-д хүлээн авдаг ч гаднах query түүний баганыг цэвэрхэн дуудах боломжгүй болно, PostgreSQL subquery in FROM must have an alias гэсэн алдаа өгнө — “FROM дахь subquery нэртэй байх ёстой.” FROM дахь subquery бүрт AS-ээр нэр өг.
Холбоотой subquery-д гаднах хүснэгтийг буруу заах. Жишээ 4-т WHERE l.member_id = m.id-ийн оронд WHERE l.member_id = l.id гэж бичвэл SQLite алдаа өгөхгүй — дотоод query өөрийн мөрүүдийг өөртэйгөө харьцуулж, гаднах гишүүнтэй ямар ч холбоогүй үр дүн өгнө. Холбоотой subquery-д гаднах хүснэгтийн alias-ийг (m) дотор зөв ашиглаж байгааг нүдээр шалгаарай.
Энэ хичээлд та subquery — хаалт доторх бүрэн SELECT-ийг гурван хэлбэрээр ашиглаж сурлаа. Scalar subquery нэг утга буцааж, WHERE эсвэл SELECT-д тоо шиг ажилладаг — "дунджаас их" гэх мэт нийлбэртэй харьцуулах асуултыг шийддэг. IN (SELECT ...) утгын жагсаалт буцааж, Бүлэг 5-ийн гараар хуулах ажлыг арилгадаг бөгөөд JOIN-оос ялгаатай нь мөр үржүүлдэггүй. FROM дахь subquery түр хүснэгт шиг ажиллаж, нийлбэрүүдийг JOIN-оос өмнө бодож мөр үржилтийг шийддэг. Холбоотой subquery гаднах мөр бүрт тусад нь ажилладаг бөгөөд EXISTS/NOT EXISTS-тэй хослоод NULL-аас ангид "байгаа/байхгүй" шалгалт өгдөг. NOT IN нь дотоод жагсаалтад ганц NULL орвол бүх мөрийг хасдаг тул болгоомжтой хэрэглэнэ. Subquery ба JOIN-ийн сонголт ихэвчлэн уншигдахуйц байдлаас хамаардаг: баганыг харуулах бол JOIN, зөвхөн шүүх бол IN/EXISTS, нийлбэртэй харьцуулах бол scalar, хоёр нийлбэрийг нэгтгэх бол FROM дахь subquery.
Дараагийн хичээлд асуулт "юу" биш, "хэр хурдан" болно. Манай найман номтой хүснэгтэд бүх query агшин зуур ажилладаг. Гэвч хагас сая мөртэй хүснэгтэд юу болох вэ? Бид ийм хүснэгтийг скриптээр үүсгэж, query-ний хугацааг жинхэнэ хэмжиж, дараа нь index — номын товьёог — нэмээд дахин хэмжинэ. Мөн index-ийн үнэ төлбөргүй биш гэдгийг, яагаад бүх баганад index тавьж болохгүйг шударгаар харна.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.