(RDB) 13 Cara Memahami Join
(justinjaffray.com)- Inner join dalam basis data relasional dapat dipahami bukan hanya sebagai sintaks SQL sederhana, tetapi sebagai struktur yang sama yang ditafsirkan berbeda dari sudut pandang kueri, nested loop, model logika, pemeriksaan tipe, dan aljabar
- Dalam tabel yang ternormalisasi, join menjadi alat paling praktis untuk mengikuti referensi dan menggabungkan kembali informasi yang disimpan tanpa duplikasi
- Dari sudut pandang implementasi, ini bisa dilihat sebagai menelusuri pasangan baris dan hanya menyisakan kombinasi yang memenuhi kondisi, atau memilih hanya kombinasi nilai yang ada di kedua relasi dari domain kolom
- Dalam model pemrograman, join dapat dijelaskan dengan
flatMap, SQLLATERAL, penyelesaian masalah N+1 pada ORM, pemeriksaan tipe berbasis trait Rust, danandThendari monad Set - Secara matematis, jalur graf, model minimum, relasi terbesar yang diizinkan, batas atas terkecil pada himpunan berurutan parsial, dan hasil kali ring dari ekspresi relasional semuanya menyingkap sifat join yang sama
Pada data yang ternormalisasi, join menjadi kueri
- Secara paling praktis, join dapat dipandang sebagai operasi untuk mengambil suatu nilai, atau menambahkan informasi redundan ke data yang sudah ada
- Contohnya dimulai dari cara menyimpan
user,country, dancountry_codedalam satu tabel- Untuk setiap nilai
countryyang sama,country_codeakan berulang sehingga menimbulkan duplikasi - Jika datanya sering berubah, semua lokasi harus diperbarui bersama-sama sehingga meningkatkan risiko kesalahan dan inefisiensi
- Untuk setiap nilai
- Dalam bentuk ternormalisasi, relasi antara
countrydancountry_codedipisahkan ke tabel lain, dan tabel pengguna hanya mereferensikancountry_id - Jika
usersdancountriesdi-INNER JOINdengancountry_id, kita bisa mendapatkan kembali bentuk asliuser,country,country_code - Penjelasan selanjutnya mengasumsikan join implisit berdasarkan kolom dengan nama yang sama, tanpa terlalu terikat secara ketat pada detail sintaks SQL
Sudut pandang implementasi: join yang menelusuri baris dan kolom
- Jika ada dua himpunan
R,Sdan predikatp, maka join menelusuri semuar ∈ R,s ∈ S, lalu hanya mengeluarkan kasus ketikap(r, s)bernilai benar- Jika hasil kali Kartesius dari dua koleksi adalah semua kemungkinan penggabungan baris, maka join adalah subset yang memenuhi kondisi tersebut
- Jika dilihat per kolom, domain setiap kolom dianggap sebagai himpunan nilai yang mungkin, lalu kombinasi nilai kolom itu ditelusuri
- Jika ada
R(a, b)danS(b, c), maka domaina,b,cditelusuri - Hanya ketika
(a, b)ada diRdan(b, c)ada diS, maka[a, b, c]dikeluarkan
- Jika ada
Join sebagai realitas alternatif yang saling kompatibel
- Contoh John dan Sally menjelaskan join sebagai cara menyisakan hanya realitas yang saling kompatibel ketika masing-masing hanya memiliki sebagian informasi
- John mengetahui kemungkinan kombinasi antara hewan peliharaannya dan hewan liar, dan Sally juga memiliki kemungkinan kombinasi antara hewan peliharaannya dan hewan liar
- Jika John memiliki dog saat hewan liar itu dog, dan Sally memiliki cat saat hewan liar itu mouse, keduanya tidak mungkin benar secara bersamaan
- Karena keduanya harus mengamati hewan liar yang sama
- Jika dua tabel di-join berdasarkan
stray, maka hanya kombinasi pet John · stray · pet Sally yang tidak saling bertentangan yang akan tersisa
Join dalam model pemrograman
flatMapadalah fungsi yang membuat array baru untuk setiap elemen array asal lalu menggabungkan hasilnya, dan ini dapat digunakan untuk mengimplementasikan joinSELECT * FROM r INNER JOIN s ON pdapat dinyatakan sebagair.flatMap(x => s.filter(y => p(x, y)))- Sintaks
LATERALpada beberapa varian SQL mengubah join menjadi bentukflatMap
- Jika sisi kanan
LATERALtidak mereferensikan kolom di sisi kiri, maka hasilnya setara dengan hasil kali Kartesius- Decorrelation kueri bergantung pada penghapusan referensi kolom di sisi kanan melalui serangkaian penulisan ulang bertahap
- Masalah N+1 yang umum pada ORM juga dapat dijelaskan lewat join
- Jika kueri tambahan dijalankan untuk setiap baris di himpunan hasil, maka pada basis data yang memakai koneksi seperti Postgres, biaya tetap tiap kueri individual menjadi besar
- Hasil dari meminta basis data untuk “menjalankan semua pengambilan ini sekaligus” adalah join seperti
users INNER JOIN countries - Pada basis data in-process seperti Sqlite, masalah ini tidak terlalu besar
Jalur graf dan model logika
- Karena relasi “menghubungkan” dua himpunan, relasi dapat dipandang sebagai graf
- Tabel
usersmenghubungkan himpunan nama pengguna dengan himpunancountry_id - Relasi yang menghubungkan
country_iddan kode negara dua huruf juga dapat digambarkan sebagai graf terpisah
- Tabel
- Jika himpunan di sisi kanan graf pertama dan himpunan di sisi kiri graf kedua berbagi vertex set yang sama, keduanya dapat dipandang sebagai satu kesatuan
- Jika kita mencantumkan semua jalur dari himpunan kiri, melalui vertex tengah, ke himpunan kanan, itulah join dari kedua relasi tersebut
- Dalam logika formal, relasi dipandang sebagai predikat, dan model adalah himpunan fakta yang membuat sekumpulan kalimat menjadi benar
- Jika
users(A, B)dancountries(B, C, D)benar, maka ada implikasi bahwaQ(A, B, C, D)benar - Bisa ada banyak model yang memenuhi kondisi ini
- Untuk memperoleh hasil yang standar, dipilih model terkecil di antara model-model yang memenuhi kondisi itu
- Model terkecil ini sama dengan hasil join
usersdancountry
- Jika
Join sebagai pemeriksaan tipe
- Sistem tipe bergaya ML sangat mirip dengan Prolog dan Datalog, sehingga dapat diekspresikan dengan cara yang mirip join
- Dalam contoh Rust, relasi didefinisikan sebagai trait
UsersdanCountryCodeberperan sebagai relasiSmudge,Sissel,Petee,Canada,UnitedStates,CA,USdidefinisikan sebagai tipe konkret
- Implementasi trait seperti
(Smudge, Canada): Usersdan(Canada, CA): CountryCodesetara dengan baris dalam relasi - Agar
(A, B, C)termasuk dalam join, harus berlaku(A, B): Usersdan(B, C): CountryCode test::<(Smudge, _, CA)>()lolos pemeriksaan tipe, tetapitest::<(Smudge, _, US)>()gagal karena(Canada, US): CountryCodetidak diimplementasikan
Join sebagai operasi monad Set
- Contoh
SomedanNonedi JavaScript dimulai dari cara menggabungkan record opsional- Jika dua record memiliki
countryyang sama, keduanya digabung danSomedikembalikan - Jika tidak kompatibel atau nilainya tidak ada,
Nonedikembalikan
- Jika dua record memiliki
andThenmembuka nilai di dalam optional lalu menerapkan fungsi penggabungan- Dengan tetap memakai fungsi
combineyang sama, container bisa diubah menjadiReluntuk memproses himpunan relasiRel.mapmenerapkan fungsi ke semua barisRel.andThenmenggabungkan relasi yang dihasilkan dari tiap baris denganflatMap
- Jika fungsi
combineyang sama dijalankan pada relasiusersdancountries, hasilnya adalah join dengan kode negara yang ditambahkan keSmudge,Sissel, danPetee
Relasi terbesar yang diizinkan dan join pada himpunan berurutan parsial
- Relasi ketiga
Tyang memiliki semua kolom dari dua relasiR,Sdidefinisikan sebagai diizinkan jika ia tidak menciptakan informasi baru- Jika suatu baris dari
Tdibatasi ke kolom milikR, maka baris itu harus ada diR - Dengan cara yang sama, jika dibatasi ke kolom milik
S, maka baris itu juga harus ada diS
- Jika suatu baris dari
- Sebagai contoh,
Smudge, Canada, UStidak diizinkan- Jika hanya dilihat dari
country,country_code, hasilnya menjadiCanada, US, dan itu bukan baris yang ada diS
- Jika hanya dilihat dari
- Relasi kosong juga diizinkan, tetapi relasi terbesar yang diizinkan memuat
Smudge-Canada-CA,Sissel-Canada-CA,Petee-United States-US - Relasi terbesar yang diizinkan inilah join dari dua relasi tersebut
- Dari sudut pandang himpunan berurutan parsial,
R ≤ Qdidefinisikan sebagai berikutQmemuat semua kolom milikR- Jika setiap baris
Qdibatasi ke kolom milikR, hasilnya adalah baris diR
- Dalam himpunan berurutan parsial ini, terdapat batas atas terkecil
R ∨ Sdari dua relasiR,S, dan ini memiliki makna yang sama dengan join relasional
Join sebagai hasil kali ring
- Relasi juga dapat dinyatakan secara aljabar
- Satu baris direpresentasikan sebagai hasil kali pasangan kolom-nilai
- Satu relasi direpresentasikan sebagai penjumlahan dari beberapa baris
- Sebagai contoh, suku hasil kali dari
user = Smudgedancountry_id = 1menjadi satu baris - Aturan tambahan diperkenalkan untuk menyederhanakan ekspresi
- Idempotence:
[x = y][x = y] = [x = y] - Contradiction:
[x = y][x = z] = 0ify ≠ z
- Idempotence:
- Jika relasi pengguna
Rdan relasi lookup negaraSdikalikan lalu dikembangkan dengan hukum distributif dan komutatif, maka suku-suku yang bertentangan akan hilang dan hanya suku yang kompatibel yang tersisa - Ekspresi yang tersisa adalah
Smudge-1-Canada-CA,Sissel-1-Canada-CA,Petee-2-United States-US, dan ini tepat sama dengan join dua relasi tersebut - Cara ini juga dapat dipandang sebagai tensor contraction
1 komentar
Komentar Hacker News
Begitu mulai memikirkan join dalam dimensi ruang, konsepnya jadi jauh lebih mudah dipahami
Jika setiap dimensi dipisah ke tabel berbeda seperti
Dim_X,Dim_Y,Dim_Zlalu diikat denganEntityIdyang sama, itu bisa dilihat sebagai cara menyusun posisi 3 dimensi suatu entitasUntuk membuat 3 dimensi, dibutuhkan setidaknya 2 inner join, dan dimensi nonspasial seperti waktu juga bisa diperluas dengan cara yang sama
Jika waktu tertentu tidak dibatasi, hasilnya menjadi laporan yang memuat semua posisi yang pernah ditempati satu entitas seiring waktu
Tipe join lain juga jadi lebih mudah dipahami sebagai variasi dari ini jika konsep skemanya sudah cukup tertanam sampai bisa “memutar” skema itu di kepala
https://dbdb.io/db/hyperdex
EntityPosition(EntityId, X, Y, Z)Tetapi dari sisi menyusun potongan berbagai dimensi dan menangani agregasi, ini mengingatkan pada data warehouse
JOIN,INNER JOIN. Menuliskan tabel diFROMlalu menaruh kondisi join di klausaWHEREsebagai persamaan terasa jauh lebih jelasKalau ada banyak
JOINbercampur di klausaFROMyang kompleks, itu sulit dibaca, dan membaca ekspresi kondisi yang setara diWHEREterasa lebih intuitifSudut pandang ke-0 adalah bahwa “join adalah operator dalam aljabar relasional”
https://en.m.wikipedia.org/wiki/Relational_algebra
Natural join
R ⋈ Sadalah himpunan kombinasi tuple yang memiliki nama atribut bersama yang sama, dan merupakan operasi relasional yang berpadanan dengan logicalAND⋈bisa dipandang sebagai hasil kali Kartesius yang memfilter baris-baris yang tidak boleh masuk ke hasil melalui predikat, dan banyak bagian SQL jadi lebih mudah dipahami dari sudut pandang iniSudah beberapa hari saya mencari materi tentang implementasi eksekusi/perencanaan query, tetapi sulit menemukan materi implementasi soal predikat, indeks yang ada, dan join
Hasil pencarian Google tercemar oleh materi penggunaan
Sejauh ini yang saya temukan hanya materi dari CMU Database Group, dan itu sangat bagus
https://pi3.informatik.uni-mannheim.de/~moer/querycompiler.p...
Kuliah TUM “Database Systems on Modern CPU Architectures” juga mungkin membantu, dan materi tahun 2020 punya rekaman kuliah lengkap
https://db.in.tum.de/teaching/ss20/moderndbs/?lang=en
https://www.sqlite.org/optoverview.html
https://www.sqlite.org/queryplanner.html
https://www.postgresql.org/docs/current/planner-optimizer.ht...
Eksekusi query dan perencanaan query pada praktiknya hampir merupakan hal yang terpisah
Untuk makalah optimisasi join, menurut saya makalah Selinger yang asli masih yang terbaik
https://courses.cs.duke.edu/compsci516/cps216/spring03/paper...
Memang tidak mendukung outer join dan teknik yang lebih efisien sudah muncul, tetapi bagi siapa pun yang melihat optimizer keluarga System R, makalah itu masih terasa familier
src/backend/optimizer/READMEmilik Postgres juga berisi banyak hal yang sulit ditemukan di tempat lainKuliah Andy Pavlo dari CMU nyaris menjadi satu-satunya materi online yang benar-benar menjelaskan hal ini, dan PDF “Building Query Compilers”, meski tidak lengkap, memuat makalah inti Moerkotte dkk., jadi layak dibaca kalau ingin membuat implementasi modern
Mencari indeks yang bisa diterapkan biasanya tidak terlalu sulit karena cukup melihat apakah ada sargable predicate, tetapi estimasi selektivitas itu sulit, dan estimasi selektivitas setelah join termasuk masalah tersulit dalam optimizer
Misalnya, jika ada
A=x AND B=y AND C=zdan hanya tersedia informasi selektivitas/kardinalitas untuk indeks(A,B)dan(B,C), memperkirakan selektivitas gabungan dari ketiga kondisi itu bukan masalah yang sederhanaBahkan ada makalah yang menuntut solver untuk “second-order cone programming” demi menyelesaikan ini
query planning, dan sekilas pun terlihat hasil yang lebih banyak mengarah ke implementasiCara ke-14 adalah multi-join, juga disebut “join optimal kasus terburuk”, tetapi namanya kurang bagus
Artinya, alih-alih menggabungkan tabel dua per dua sambil terus membuat hasil antara, 3 tabel atau lebih digabungkan sekaligus tanpa hasil antara
Ada tulisan blog terkait dan video singkat di https://relational.ai/blog/dovetail-join, dan makalah aslinya ada di https://dl.acm.org/doi/pdf/10.1145/3180143
Saya bekerja di RelationalAI, dan algoritme join baru ini, yang telah diteliti di dunia akademik selama sekitar 10 tahun, sedang kami dan beberapa perusahaan database rintisan lain bawa ke pasar
https://justinjaffray.com/a-gentle-ish-introduction-to-worst...
ANDpada join menjadiNOR, dan Tetris memanfaatkan hal iniBatas kasus terburuk tidak menjadi lebih ketat daripada WCOJ stateless/streaming, tetapi data nyata sering kali memiliki sertifikat kotak yang jauh lebih kecil
Saya belum melihat apakah dovetail join mendukung kueri rekursif, yaitu datalog arbitrer di mana hanya relasi output yang ditentukan dan relasi antara ditangani sendiri oleh mesin
Saya penasaran apakah kueri semacam itu didukung
Perlu lebih banyak tulisan seperti ini yang menunjukkan nuansa model relasional terutama kepada pengembang level aplikasi
Penjelasan dan penelusuran dari sudut pandang pemrograman fungsional juga ringkas dan meyakinkan
Sepertinya kesempatan lain untuk mengajarkan masalah N+1 terlewatkan
Melakukan join ke indeks yang tidak terklaster juga tetap N+1, hanya saja N+1 di atas disk, bukan N+1 yang bolak-balik lewat jaringan dan disk
Join internal adalah perkalian Kartesius dengan syarat
Join internal dengan kondisi equi-join langsung menghasilkan syaratnya, sedangkan kondisi non-equi join memerlukan evaluasi nyata
Penjelasannya bagus. Pernyataan bahwa “cara yang benar adalah menormalkan tabel” benar untuk database transaksional, tetapi di data warehouse, tingkat denormalisasi tertentu diterima luas
Contoh normalisasi itu mengingatkan saya pada masa ketika saya merancang tabel karena mengira kunci utama numerik lebih cepat daripada string
Akibatnya muncul
idyang tidak bermakna, dan untuk mendapatkan nilai unik yang sebenarnya diinginkan, perlu joinSuatu hari saya menyadari bahwa memakai kunci unik yang sama di dua tabel bisa mengurangi join, dan itu sederhana tetapi efektif
idunik di setiap tabel. Itu membantu untuk logging dan membuat saya tidak perlu memikirkan kunci “sebenarnya” yang terdiri dari beberapa fieldSebagai gantinya, saya memasang indeks unik pada nilai string, dan yang lebih penting, menaruh batasan integritas di sana
Tabel yang penuh string bermakna jauh lebih mudah dibaca daripada tabel yang penuh
idnumerik atau UUID