SEN2104 · 13. hafta · Query Processing and Query Optimization

Sorgu işleme ve optimizasyon: join algoritmaları, denklik kuralları, tahmin

Bir sorgunun hangi adımlardan geçtiği, nested-loop/block/indexed/merge/hash join maliyetlerinin nasıl hesaplandığı ve optimizer'ın sorgu ağacını nasıl yeniden yazdığı.

query processingparsingquery evaluation planquery optimizationblock transferseekexternal sort-mergerunnested-loop joinblock nested-loop joinindexed nested-loop joinmerge joinhash joinbuild inputprobe inputequivalence rulesheuristic optimizationquery treeselectivityV(A, r)join size estimation

Geçen hafta tek bir tablodan seçim yapmanın maliyetini hesapladık. Bu hafta sorgu birden çok tabloyu birleştiriyor. Aynı SQL sorgusu için onlarca farklı çalışma planı olabilir ve aralarında binlerce kat maliyet farkı çıkabilir. Optimizer’ın işi bunlardan ucuz olanı bulmak. Sınavda üç soru tipi var: join maliyeti hesapla, iki planı karşılaştır, sorgu ağacını denklik kurallarıyla yeniden yaz.

Altın kurallar:

  1. Maliyet = blok transferi + seek. Seek sayısını unutma, sorunun yarısı oradan gelir.
  2. Nested-loop türlerinde küçük ilişki dışa konur.
  3. Seçimi (σ\sigma) olabildiğince aşağı it. Join’e giren satır sayısını azaltmak en büyük kazançtır.
  4. Denklik kuralı sonucu değiştirmez. Sadece maliyeti değiştirir.

Sorgu işlemenin adımları

  1. Parsing and translation: SQL’in sözdizimi kontrol edilir, tablo ve sütun isimleri doğrulanır, sorgu ilişkisel cebir ifadesine çevrilir.
  2. Optimization: eşdeğer cebir ifadeleri ve her işlem için algoritmalar düşünülür. Her plan için maliyet tahmin edilir (istatistiklerle), en ucuzu seçilir. Sonuç bir değerlendirme planıdır (query evaluation plan): her düğümünde hangi algoritmanın kullanılacağı yazan bir ağaç.
  3. Evaluation: plan çalıştırılır.

Maliyet ölçüsü: bb blok transferi ve SS seek için

maliyet=b⋅tT+S⋅tS\text{maliyet} = b \cdot t_T + S \cdot t_S

Bu sayfada da tT=0.1t_T = 0.1 ms, tS=4t_S = 4 ms.

Dış sıralama (external sort-merge)

Tablo belleğe sığmıyorsa sıralama iki aşamada olur. MM = bellekteki buffer blok sayısı.

  1. Run oluşturma: MM bloğu oku, bellekte sırala, run olarak yaz. ⌈br/M⌉\lceil b_r / M \rceil run çıkar.
  2. Birleştirme: her geçişte M−1M - 1 run birleştirilir (1 blok çıktı için). Geçiş sayısı ⌈log⁡M−1(br/M)⌉\lceil \log_{M-1}(b_r / M) \rceil.

transfer=br(2⌈log⁡M−1brM⌉+1)\text{transfer} = b_r \left( 2 \left\lceil \log_{M-1} \frac{b_r}{M} \right\rceil + 1 \right)

Örnek: br=400b_r = 400, M=11M = 11. Run sayısı ⌈400/11⌉=37\lceil 400/11 \rceil = 37. Her geçişte 10 run birleşir: 37→4→137 \to 4 \to 1, 2 geçiş. Transfer 400⋅(2⋅2+1)=2000400 \cdot (2 \cdot 2 + 1) = 2000. Son sonucun diske yazılması sayılmaz, çünkü genelde bir sonraki işleme doğrudan aktarılır.

Join algoritmaları

Gövdedeki örnek: rr = takes (nr=10000n_r = 10000, br=400b_r = 400), ss = student (ns=5000n_s = 5000, bs=100b_s = 100). Join koşulu takes.stu_id = student.stu_id.

Nested-loop join

for each tuple t_r in r:
    for each tuple t_s in s:
        if (t_r, t_s) koşulu sağlıyorsa çıktıya yaz

En kötü durumda (her ilişkiye tek buffer):

nr⋅bs+br transfer,nr+br seekn_r \cdot b_s + b_r \text{ transfer}, \qquad n_r + b_r \text{ seek}

takes dışta: 10000⋅100+400=1 000 40010000 \cdot 100 + 400 = 1\,000\,400 transfer, 1040010400 seek. Süre 100040+41600=141640100040 + 41600 = 141640 ms, yaklaşık 2.4 dakika. student dışta: 5000⋅400+100=2 000 1005000 \cdot 400 + 100 = 2\,000\,100 transfer. Burada dışın tuple sayısı çarpan olduğu için az tuple’lı olan dışta daha iyi.

En iyi durum: küçük ilişki belleğe tamamen sığıyorsa her ikisi bir kez okunur: br+bs=500b_r + b_s = 500 transfer, 2 seek.

Block nested-loop join

Tuple tuple değil, blok blok eşleştir: dışın her bloğu için iç ilişki bir kez taranır.

br⋅bs+br transfer,2br seekb_r \cdot b_s + b_r \text{ transfer}, \qquad 2 b_r \text{ seek}

takes dışta: 400⋅100+400=40400400 \cdot 100 + 400 = 40400 transfer, 800 seek. student dışta: 100⋅400+100=40100100 \cdot 400 + 100 = 40100 transfer, 200 seek. Bu sefer de küçük ilişki dışta kazanıyor.

MM buffer varsa dış ilişkiye M−2M - 2 blok ayrılır (bir iç, bir çıktı):

⌈brM−2⌉bs+br transfer,2⌈brM−2⌉ seek\left\lceil \frac{b_r}{M-2} \right\rceil b_s + b_r \text{ transfer}, \qquad 2 \left\lceil \frac{b_r}{M-2} \right\rceil \text{ seek}

M=12M = 12, student dışta: ⌈100/10⌉=10\lceil 100/10 \rceil = 10 parça, 10⋅400+100=410010 \cdot 400 + 100 = 4100 transfer, 20 seek.

Indexed nested-loop join

İç ilişkide join özniteliği üzerinde indeks varsa iç ilişkiyi taramak yerine her dış tuple için indekste arama yapılır. cc = bir arama + eşleşeni getirme maliyeti.

br(tT+tS)+nr⋅cb_r (t_T + t_S) + n_r \cdot c

takes dışta, student.stu_id üzerinde hi=3h_i = 3 B+ ağacı: anahtarda eşitlik olduğu için c=hi+1=4c = h_i + 1 = 4 blok erişimi. Erişim sayısı 400+10000⋅4=40400400 + 10000 \cdot 4 = 40400. Her biri seek + transfer olduğundan süre olarak bu, block nested-loop’tan pahalıdır. Indexed nested-loop, dış ilişki küçükken (örneğin önce sıkı bir σ\sigma uygulanmışsa) parlar.

Merge join

İki ilişki join özniteliğine göre sıralıysa ikisi paralel taranır, bir kez okunur:

br+bs transferb_r + b_s \text{ transfer}

Örnekte 400+100=500400 + 100 = 500. Sıralı değillerse önce sıralama maliyeti eklenir. M=11M = 11 ile takes sıralaması 2000, student sıralaması (⌈100/11⌉=10\lceil 100/11 \rceil = 10 run, 1 geçiş) 100⋅3=300100 \cdot 3 = 300 transfer. Toplam 2000+300+500=28002000 + 300 + 500 = 2800. Sadece eşitlik ve doğal join (equi-join) için kullanılır.

Hash join

  1. Bölümleme (partitioning): iki ilişki aynı hash fonksiyonuyla nhn_h parçaya bölünür. Eşleşebilecek tuple’lar aynı numaralı parçalara düşer.
  2. Her ii için sis_i belleğe alınır ve bellekte hash tablosu kurulur (build input), sonra rir_i okunup bu tabloda aranır (probe input).

Küçük ilişki build input olur; her sis_i belleğe sığmalı. Özyinelemeli bölümleme gerekmiyorsa:

3(br+bs) transfer3 (b_r + b_s) \text{ transfer}

Bölümlemede okuma + yazma 2(br+bs)2(b_r + b_s), build/probe aşamasında bir okuma (br+bs)(b_r + b_s). Örnekte 3⋅500=15003 \cdot 500 = 1500.

Özet karşılaştırma (takes ⋈ student)

AlgoritmaTransferNot
Nested-loop, takes dışta1 000 400en kötü
Block nested-loop, student dışta40 100
Block nested-loop, M=12M = 124 100
Indexed nested-loop, c=4c = 440 400 erişimhepsi rastgele
Merge join + iki sıralama2 800sonuç sıralı çıkar
Hash join1 500eşitlik join’i

TUZAK · formüllerde nn mi bb mi? Basit nested-loop’ta çarpan dışın tuple sayısı nrn_r, block nested-loop’ta dışın blok sayısı brb_r. Indexed nested-loop’ta yine nrn_r. Sınavda en sık kayıp puan buradan çıkar.

Denklik kuralları (equivalence rules)

İki cebir ifadesi her veritabanı örneğinde aynı sonucu veriyorsa eşdeğerdir. Optimizer’ın kullandığı başlıca kurallar:

Kuralİfade
Seçim kaskadıσθ1∧θ2(E)=σθ1(σθ2(E))\sigma_{\theta_1 \wedge \theta_2}(E) = \sigma_{\theta_1}(\sigma_{\theta_2}(E))
Seçim değişmeliσθ1(σθ2(E))=σθ2(σθ1(E))\sigma_{\theta_1}(\sigma_{\theta_2}(E)) = \sigma_{\theta_2}(\sigma_{\theta_1}(E))
Projeksiyon kaskadıπL1(πL2(E))=πL1(E)\pi_{L_1}(\pi_{L_2}(E)) = \pi_{L_1}(E), L1⊆L2L_1 \subseteq L_2 ise
σ\sigma ve ×\timesσθ(E1×E2)=E1⋈θE2\sigma_{\theta}(E_1 \times E_2) = E_1 \bowtie_{\theta} E_2
Join değişmeliE1⋈E2=E2⋈E1E_1 \bowtie E_2 = E_2 \bowtie E_1
Join birleşmeli(E1⋈E2)⋈E3=E1⋈(E2⋈E3)(E_1 \bowtie E_2) \bowtie E_3 = E_1 \bowtie (E_2 \bowtie E_3)
Seçimi aşağı itmeσθ(E1⋈E2)=σθ(E1)⋈E2\sigma_{\theta}(E_1 \bowtie E_2) = \sigma_{\theta}(E_1) \bowtie E_2, θ\theta sadece E1E_1‘in özniteliklerini kullanıyorsa
Projeksiyonu aşağı itmeπL(E1⋈θE2)=πL1(E1)⋈θπL2(E2)\pi_L(E_1 \bowtie_\theta E_2) = \pi_{L_1}(E_1) \bowtie_\theta \pi_{L_2}(E_2), LiL_i hem LL‘deki hem θ\theta‘daki öznitelikleri içermeli
Küme işlemleri∪\cup ve ∩\cap değişmeli ve birleşmeli; σ\sigma bunlara ve −- işlemine dağılır

Join değişmeliliği sütun sırasını değiştirir, ama ilişkide sütunlar isimle tanımlandığı için sonuç aynı ilişkidir.

Sezgisel optimizasyon (heuristic optimization)

Tüm planları denemek pahalı. Sezgisel kurallar çoğu durumda iyi plan verir:

  1. Konjonktif seçimleri kaskadla parçala.
  2. Her seçimi ağaçta olabildiğince aşağı it.
  3. En kısıtlayıcı (en az satır bırakan) seçim ve join’i önce yap.
  4. σ\sigma + ×\times çiftini ⋈\bowtie‘a çevir. Kartezyen çarpımdan kaç.
  5. Projeksiyonu erken yap, gereksiz sütunları at. Join için gereken sütunları tutmayı unutma.

Örnek: sorgu ağacını dönüştürmek

Örnek üniversite veritabanında: “CS bölümündeki öğrencilerden 3 kredilik bir ders almış olanların adları.” course tablosunda da dept_name olduğu için onu c_dept diye yeniden adlandırıyoruz; yoksa doğal join öğrencinin bölümüyle dersin bölümünü de eşitlemeye çalışır.

Saf çeviri:

πname(σdept_name=′CS′∧credits=3(student⋈(takes⋈course)))\pi_{name}\big(\sigma_{dept\_name='CS' \wedge credits=3}(\text{student} \bowtie (\text{takes} \bowtie \text{course}))\big)

Kaskad + seçimi aşağı itme + projeksiyonu erken yapma:

πname(πstu_id, name(σdept_name=′CS′(student))⋈πstu_id(takes⋈σcredits=3(course)))\pi_{name}\Big(\pi_{stu\_id,\, name}(\sigma_{dept\_name='CS'}(\text{student})) \bowtie \pi_{stu\_id}\big(\text{takes} \bowtie \sigma_{credits=3}(\text{course})\big)\Big)

ara sonuç boyutları (örnek DB)        saf plan   optimize plan
student ⋈ takes ⋈ course              14         -
σ dept_name='CS'(student)             -          3
σ credits=3(course)                   -          4
takes ⋈ σ(course)                     -          5
sonuç                                 Ada        Ada

İki plan aynı sonucu (sadece Ada) verir. Saf plan önce 14 satırlık bir join üretip sonra eliyor; optimize plan join’e 3 ve 5 satırla giriyor. Gerçek boyutlarda bu fark milyonlarca satırdır.

TUZAK · doğal join ve aynı isimli sütun. Yeniden adlandırmadan student ⋈ takes ⋈ course yazarsan dept_name de eşitlenir ve örnek veritabanında 14 yerine 9 satır çıkar: öğrencinin kendi bölümü dışından aldığı dersler kaybolur. Bu bir optimizasyon değil, yanlış sorgudur.

İstatistikler ve boyut tahmini

Optimizer planın maliyetini tahmin etmek için katalogdaki istatistikleri kullanır: nrn_r, brb_r, frf_r, ve V(A,r)V(A, r), yani rr‘de AA‘nın farklı değer sayısı.

İfadeTahmini satır sayısı
σA=v(r)\sigma_{A = v}(r)nr/V(A,r)n_r / V(A, r)
σA≤v(r)\sigma_{A \le v}(r)nr⋅v−min⁡(A)max⁡(A)−min⁡(A)n_r \cdot \frac{v - \min(A)}{\max(A) - \min(A)}
σθ1∧θ2(r)\sigma_{\theta_1 \wedge \theta_2}(r)nr⋅s1nr⋅s2nrn_r \cdot \frac{s_1}{n_r} \cdot \frac{s_2}{n_r} (bağımsızlık varsayımı)
r⋈sr \bowtie s, ortak öznitelik ss‘nin anahtarı≤nr\le n_r; yabancı anahtarsa tam nrn_r
r⋈sr \bowtie s, ortak öznitelik anahtar değilmin⁡(nrnsV(A,s),nrnsV(A,r))\min\left(\frac{n_r n_s}{V(A,s)}, \frac{n_r n_s}{V(A,r)}\right)

Örnek: n=5000n = 5000 öğrenci, V(dept_name)=20V(dept\_name) = 20. dept_name = 'CS' tahmini 250250. tot_cred 0 ile 240 arasında ise tot_cred <= 60 tahmini 5000⋅60/240=12505000 \cdot 60/240 = 1250. İkisi birden: 5000⋅0.05⋅0.25=62.55000 \cdot 0.05 \cdot 0.25 = 62.5, yani yaklaşık 63 satır.

Tahmin bir varsayımdır. Örnek veritabanımızda student 7 satır ve COUNT(DISTINCT dept_name) = 3 (NULL sayılmaz). Tahmin 7/3≈2.337/3 \approx 2.33, gerçekte CS’de 3 öğrenci var. Dağılım eşit değilse tahmin sapar; gerçek sistemler bu yüzden histogram tutar.

Sık yapılan hatalar

Yanlış düşünceDoğrusu
Nested-loop’ta br⋅bsb_r \cdot b_sTuple tabanlıda nr⋅bs+brn_r \cdot b_s + b_r; br⋅bsb_r \cdot b_s block nested-loop
Büyük ilişki dışta olsunNested-loop türlerinde küçük ilişki dışta
Seek’i atlamakNLJ’de nr+brn_r + b_r, BNLJ’de 2br2b_r seek; seek transferden 40 kat pahalı
MM bufferın hepsi dış ilişkiyeM−2M - 2: bir blok iç ilişki, bir blok çıktı
Dış sıralamada geçiş sayısı log⁡M\log_MBirleştirmede M−1M - 1 yol: ⌈log⁡M−1(br/M)⌉\lceil \log_{M-1}(b_r/M) \rceil
Merge join her zaman br+bsb_r + b_sSadece zaten sıralıysa; değilse sıralama maliyeti eklenir
Hash join’de büyük ilişki build inputKüçük ilişki build input, parçaları belleğe sığmalı
Seçimi join’in istediğin koluna indirSadece koşuldaki tüm öznitelikler o kolda varsa
Projeksiyonu erken yaparken join sütununu atJoin özniteliği üst seviyede gerekiyorsa tutulmalı
min⁡\min yerine max⁡\max ile join tahminiDaha sıkı olan küçük değer: büyük VV‘ye böl

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1kolay

Put the steps of query processing in the correct order: optimization, parsing and translation, evaluation.

Cevabı göster
parsing and translation, optimization, evaluation

Önce SQL sözdizimi kontrol edilir ve ilişkisel cebir ifadesine çevrilir (parsing and translation).
Sonra optimizer eşdeğer planlar arasından tahmini en ucuzunu seçer (optimization).
En son evaluation engine seçilen planı çalıştırır ve sonucu döndürür.

Soru 2orta

Relation rr has nr=6000n_r = 6000 tuples in br=300b_r = 300 blocks; ss has ns=1500n_s = 1500 tuples in bs=60b_s = 60 blocks. Using a simple (tuple) nested-loop join with rr as the outer relation and only one buffer block per relation (worst case), give the number of block transfers and seeks.

Cevabı göster
360300 transfers, 6300 seeks

Dış ilişkinin her tuple'ı için iç ilişkinin tamamı okunur: nr⋅bs=6000⋅60=360000n_r \cdot b_s = 6000 \cdot 60 = 360000.
Dış ilişkinin kendisi bir kez okunur: +br=300+ b_r = 300. Toplam 360300 transfer.
Seek: her dış tuple için iç ilişkiye bir seek (nrn_r) ve dış ilişkinin her bloğu için bir seek (brb_r): 6000+300=63006000 + 300 = 6300.

Soru 3orta

Same rr (br=300b_r = 300) and ss (bs=60b_s = 60). For a block nested-loop join (worst case, one buffer block each), compute the block transfers with rr as outer and with ss as outer. Which should be the outer relation?

Cevabı göster
r outer: 18300, s outer: 18060; s should be outer

Formül: bdıs¸⋅bic¸+bdıs¸b_{\text{dış}} \cdot b_{\text{iç}} + b_{\text{dış}} transfer, 2bdıs¸2 b_{\text{dış}} seek.rr dış: 300⋅60+300=18300300 \cdot 60 + 300 = 18300 transfer, 600 seek.ss dış: 60⋅300+60=1806060 \cdot 300 + 60 = 18060 transfer, 120 seek.
Çarpım kısmı aynı, fark ikinci terimde ve seek sayısında. Küçük ilişki dışta olmalı: ss.

Soru 4orta

Block nested-loop join of rr (br=300b_r = 300) and ss (bs=60b_s = 60) with M=22M = 22 memory buffers, ss as outer. Give block transfers and seeks.

Cevabı göster
960 transfers, 6 seeks

M−2=20M - 2 = 20 blok dış ilişkiye ayrılır (1 blok iç ilişki, 1 blok çıktı).
Dış ilişki ⌈60/20⌉=3\lceil 60/20 \rceil = 3 parçada okunur. Her parça için iç ilişki bir kez taranır.
Transfer: 3⋅300+60=9603 \cdot 300 + 60 = 960. Seek: 2⋅3=62 \cdot 3 = 6.
Tek bufferlı versiyondaki 18060 transfer 960'a indi.

Soru 5zor

Indexed nested-loop join: rr (nr=6000n_r = 6000, br=300b_r = 300) is the outer relation and ss has a B+ tree index on the join attribute. Each index lookup plus fetching the matching tuple costs c=3c = 3 block accesses. What is the total number of block accesses? If instead ss (ns=1500n_s = 1500, bs=60b_s = 60) is outer and rr has an index with the same cc, what is the cost?

Cevabı göster
18300; 4560

Formül: bdıs¸+ndıs¸⋅cb_{\text{dış}} + n_{\text{dış}} \cdot c.rr dış: 300+6000⋅3=18300300 + 6000 \cdot 3 = 18300.ss dış: 60+1500⋅3=456060 + 1500 \cdot 3 = 4560.
Indexed nested-loop'ta dış ilişkinin tuple sayısı belirleyici. Az tuple'lı ilişkiyi dışa koymak ucuz.

Soru 6orta

Both rr (br=300b_r = 300) and ss (bs=60b_s = 60) are already sorted on the join attribute. How many block transfers does a merge join need (ignore the output)?

Cevabı göster
360

İki sıralı ilişki aynı anda birer kez taranır: br+bs=300+60=360b_r + b_s = 300 + 60 = 360 transfer.
Join değerinde çok sayıda tekrar yoksa (aynı değerli tuple'lar belleğe sığıyorsa) ek okuma olmaz.

Soru 7zor

External sort-merge of a relation with br=300b_r = 300 blocks using M=7M = 7 buffer blocks. How many initial runs are created, how many merge passes are needed, and what is the total number of block transfers (do not count writing the final result)?

Cevabı göster
43 runs, 3 passes, 2100 transfers

Başlangıç run sayısı: ⌈br/M⌉=⌈300/7⌉=43\lceil b_r / M \rceil = \lceil 300/7 \rceil = 43.
Her geçişte M−1=6M - 1 = 6 run birleşir. Geçiş sayısı ⌈log⁡643⌉\lceil \log_6 43 \rceil; log⁡643≈2.10\log_6 43 \approx 2.10, yani 3 (43 → 8 → 2 → 1).
Transfer: br(2⌈log⁡M−1(br/M)⌉+1)=300⋅(2⋅3+1)=2100b_r (2 \lceil \log_{M-1}(b_r/M) \rceil + 1) = 300 \cdot (2 \cdot 3 + 1) = 2100.
Run oluşturma 1 okuma + 1 yazma, her geçiş 1 okuma + 1 yazma, son geçişin yazması sayılmaz.

Soru 8orta

For rr (br=300b_r = 300) and ss (bs=60b_s = 60), both unsorted, compare a hash join (no recursive partitioning, ignore partially filled blocks) with sort + merge join where sorting rr costs 2100 and sorting ss costs 300 transfers. Which is cheaper?

Cevabı göster
hash 1080 vs sort-merge 2760: hash join

Hash join: iki ilişki bölümlenirken okunup yazılır (2(br+bs)2(b_r + b_s)), sonra build/probe aşamasında bir kez daha okunur (br+bsb_r + b_s): 3⋅(300+60)=10803 \cdot (300 + 60) = 1080.
Sort-merge: 2100+300+(300+60)=27602100 + 300 + (300 + 60) = 2760.
Hash join daha ucuz. Ama sonucun join anahtarına göre sıralı istenmesi gibi durumlarda merge join avantaj kazanabilir.

Soru 9kolay

Relation instructor has n=6000n = 6000 tuples and V(dept_name,instructor)=40V(\text{dept\_name}, \text{instructor}) = 40. Estimate the size of σdept_name=′EE′(instructor)\sigma_{dept\_name = 'EE'}(\text{instructor}). Also estimate σsalary≤30\sigma_{salary \le 30} (salary in thousands) if salaries range uniformly from 10 to 90.

Cevabı göster
150; 1500

Eşitlik: değerlerin eşit dağıldığı varsayılır, nr/V(A,r)=6000/40=150n_r / V(A, r) = 6000 / 40 = 150.
Karşılaştırma: nr⋅v−min⁡(A)max⁡(A)−min⁡(A)=6000⋅30−1090−10=6000⋅0.25=1500n_r \cdot \frac{v - \min(A)}{\max(A) - \min(A)} = 6000 \cdot \frac{30 - 10}{90 - 10} = 6000 \cdot 0.25 = 1500.

Soru 10orta

takes has 6000 tuples and student has 1500 tuples. takes.stu_id is a foreign key referencing the primary key student.stu_id (NOT NULL). Estimate the size of takes⋈student\text{takes} \bowtie \text{student}.

Cevabı göster
6000

Ortak öznitelik student için anahtar ve takes.stu_id yabancı anahtar. Her takes tuple'ı tam olarak bir student tuple'ıyla eşleşir.
Sonuç tam olarak ntakes=6000n_{takes} = 6000 tuple. Genel kural: ortak öznitelik ss'nin anahtarıysa join en fazla nrn_r tuple verir.

Soru 11orta

On the sample university database, rewrite σdept_name=′EE′(student⋈takes)\sigma_{dept\_name = 'EE'}(\text{student} \bowtie \text{takes}) by pushing the selection down. How many tuples does the result have?

Cevabı göster
σ_dept_name='EE'(student) ⋈ takes; 3 tuples

dept_name sadece student'ta var, bu yüzden seçim join'in student koluna inebilir: σdept_name=′EE′(student)⋈takes\sigma_{dept\_name='EE'}(\text{student}) \bowtie \text{takes}.
EE öğrencileri: S3 (Cem) ve S6 (Firat). S6 hiç ders almamış. S3'ün üç kaydı var: EE210, MA101, CS101.
Sonuç 3 tuple. Join'e 7 yerine 2 student tuple'ı girer.

Soru 12zor

r(A,B)r(A, B) has 1000 tuples, s(B,C)s(B, C) has 3000 tuples, V(B,r)=100V(B, r) = 100 and V(B,s)=200V(B, s) = 200. BB is not a key of either relation. Estimate the size of r⋈sr \bowtie s.

Cevabı göster
15000

İki tahmin: nrnsV(B,s)=3⋅106200=15000\frac{n_r n_s}{V(B, s)} = \frac{3 \cdot 10^6}{200} = 15000 ve nrnsV(B,r)=3⋅106100=30000\frac{n_r n_s}{V(B, r)} = \frac{3 \cdot 10^6}{100} = 30000.
Küçük olanı (daha sıkı tahmin) alınır: min⁡=15000\min = 15000. Bu, büyük VV değerine bölmek demek.

Doğrulama: Tüm join, dış sıralama ve boyut tahmini sayıları node ile formüllerden hesaplandı; denklik kuralları (kaskad, seçimi aşağı itme, join değişme/birleşme) ve sorgu ağacı dönüşümü örnek üniversite DB'sinde hem ilişkisel cebir (JS küme işlemleri) hem node:sqlite ile çalıştırılıp sonuçların aynı olduğu kontrol edildi (verify/SEN2104/13.mjs).

Deftere not kartı

adımlar: parse+translate → optimize (plan seç) → evaluate maliyet: b transfer * t_T + S seek * t_S (CPU ihmal) NLJ: n_r*b_s + b_r transfer, n_r + b_r seek (küçük bellekte: b_r + b_s) BNLJ: b_r*b_s + b_r transfer, 2b_r seek M buffer: ceil(b_r/(M-2))*b_s + b_r INLJ: b_r + n_r*c (dışın TUPLE sayısı önemli) merge (sıralı): b_r + b_s + sıralama maliyeti dış sıralama: run = ceil(b/M), geçiş = ceil(log_{M-1}(b/M)), transfer b(2*geçiş+1) hash join: 3(b_r + b_s), küçük ilişki build input σ_{A=v}: n_r/V(A,r) σ_{A<=v}: n_r(v-min)/(max-min) join: ortak öznitelik s'nin anahtarı → <= n_r; FK ise = n_r genel: min(n_r n_s / V(A,s), n_r n_s / V(A,r)) sezgisel: σ'yı aşağı it, π'yi erken yap, en seçici σ ve join önce, × yerine ⋈