Apa yang lebih efisien, klausa mana atau gabungan dengan jutaan tabel baris plus?

17

Kami menjalankan situs web yang memiliki 250MM baris dalam satu tabel dan di tabel lain yang kami gabungkan untuk sebagian besar kueri yang memiliki hanya di bawah 15MM baris.

Struktur sampel:

MasterTable (Id, UserId, Created, Updated...) -- 15MM Rows
DetailsTable (Id, MasterId, SomeColumn...) -- 250MM Rows
UserTable (Id, Role, Created, UserName...) -- 12K Rows

Kami secara teratur harus melakukan beberapa pertanyaan terhadap semua tabel ini. Salah satunya adalah meraih statistik untuk pengguna gratis (~ 10k pengguna gratis).

Select Count(1) from DetailsTable dt 
join MasterTable mt on mt.Id = dt.MasterId 
join UserTable ut on ut.Id = mt.UserId 
where ut.Role is null and mt.created between @date1 and @date2

Masalahnya adalah permintaan ini beberapa kali akan berjalan sangat lama karena fakta bahwa sambungan terjadi jauh sebelum di mana.

Dalam hal ini apakah akan lebih bijaksana untuk menggunakan where daripada join atau mungkin where column in(...)?

Jeremy Boyd
sumber
1
Database dan versi apa?
Leigh Riffel
1
Sudahkah Anda mencoba keduanya?
gbn
Jika ini adalah Oracle saya akan membuat indeks berbasis fungsi untuk UserTable pada NVL2 (Peran, NULL, ID), tetapi ini terlihat seperti DB lain.
Leigh Riffel

Jawaban:

20

Untuk RDBMS modern tidak ada perbedaan antara "JOIN eksplisit" dan "JOIN-in-the-WHERE" (jika semua JOIN adalah INNER) berkaitan dengan kinerja dan rencana kueri.

Sintaks JOIN eksplisit lebih jelas dan kurang ambigu (lihat tautan di bawah)

Sekarang, GABUNG-sebelum-DI MANA adalah pemrosesan logis, bukan pemrosesan aktual dan pengoptimal modern cukup pintar untuk menyadari hal ini.

Masalah Anda di sini kemungkinan besar adalah pengindeksan.

Tolong tunjukkan kami semua indeks dan kunci pada tabel ini. Dan rencana kueri

Catatan: pertanyaan ini akan ditutup pada StackOverflow karena menjadi duplikat sekarang ... COUNT (1) vs COUNT (*) juga merupakan mitos rusak lainnya.

gbn
sumber
2
BUKAN SELALU BENAR bahwa tidak ada perbedaan antara joindan whereklausa. Saya mengoptimalkan kueri yang berjalan lama sepanjang waktu dan terkadang kueri yang menggunakan whereklausa berkinerja lebih baik daripada yang menggunakan joinfaktor hingga 70x. Jika sesederhana dan semudah itu, hidup akan menjadi pelangi dan unicorn. Dan ini bukan tentang beberapa mesin tidak dikenal kuno - sekarang saya melihat 70x keuntungan dari whereklausa di SQL 2012.
ajeh
Lebih jauh lagi, saya sering mengamati rencana yang sama persis dari kedua pendekatan dan mengisolasi kueri melakukan persis sama, tetapi ketika wherekueri klausa berjalan dalam batch besar itu seharusnya menjadi bagian dari, itu mengungguli joinkueri dengan margin besar. Query SQL tidak dieksekusi dalam ruang hampa - mereka dipengaruhi oleh sisa muatan server, dan seringkali wherepermintaan klausa berjalan dengan cukup baik, yang merupakan gangguan karena joinsintaks memang jauh lebih bersih.
ajeh
3
@ajeh: Saya akan menyarankan bahwa pengalaman Anda sangat tidak khas. Anda memiliki masalah yang lebih besar dengan kueri jika Anda memiliki perbedaan x70: sesederhana itu
gbn
5

Anda harus mengubah permintaan secara bersamaan

Coba lakukan klausa WHERE sebelumnya dan GABUNG nanti

Select Count(1) from DetailsTable dt
join (Select UserId,Id FROM MasterTable where
created between @date1 and @date2) mt on mt.Id = dt.MasterId 
join (Select Id FROM UserTable WHERE Role is NULL) ut
on ut.Id = mt.UserId;

Bahkan jika Anda menjalankan paket EXPLAIN pada permintaan refactored ini dan terlihat lebih buruk dari aslinya, coba saja. Tabel temp yang dibuat secara internal akan melakukan penggabungan kartesian tetapi tabel tersebut lebih kecil untuk dikerjakan.

Saya mendapat ide ini dari video YouTube ini .

Saya mencoba prinsip-prinsip dari video dalam pertanyaan yang sangat kompleks di StackOverflow dan mendapat hadiah 200 poin.

@ GBN disebutkan memastikan Anda memiliki indeks yang tepat di tempat. Dalam hal ini, silakan indeks kolom yang dibuat di MasterTable.

Cobalah !!!

UPDATE 2011-06-24 22:31 EDT

Anda harus menjalankan kueri ini:

SELECT COUNT(1) AllRoles FROM UserTable;
SELECT COUNT(1) NullRoles FROM UserTable WHERE Role is NULL;

Jika NullRoles X 20 <AllRoles (dengan kata lain, jika NullRoles kurang dari 5% dari baris tabel), Anda harus membuat indeks non-unik Peran di UserTable. Jika tidak, tabel penuh UserTable akan cukup karena Pengoptimal Permintaan mungkin mengesampingkan penggunaan indeks.

UPDATE 2011-06-25 12:40 EDT

Karena saya seorang DBA MySQL, metode saya dalam melakukan sesuatu tidak perlu mempercayai MySQL Query Optimizer melalui pesimisme positif dan bersikap konservatif. Jadi, saya akan mencoba refactoring kueri atau membuat indeks yang diperlukan untuk mengatasi kebiasaan buruk tersembunyi MySQL Query Optimizer. @ gbn's jawaban tampaknya lebih lengkap karena SQL Server mungkin memiliki lebih banyak "kesehatan pikiran" mengevaluasi permintaan.

RolandoMySQLDBA
sumber
0

Kami memiliki tabel [Detail] tentang 75M baris; tabel [Master] sekitar 400K baris dan tabel [Item] terkait yang memiliki 7 baris - selalu dan selamanya. Ini menyimpan set kecil "Item number" (1-7) dan memodelkan bentuk kertas, jutaan di antaranya dicetak dan didistribusikan setiap bulan. Permintaan tercepat adalah yang paling tidak Anda pikirkan terlebih dahulu, yang melibatkan penggunaan Cartesian Join. IIRC, itu seperti:

SELECT m.order_id, i.line_nr, d.Item_amt
FROM Master m, Item i 
INNER JOIN Detail d ON m.order_id = d.order_id

Meskipun ada tautan “id” logis antara [Item] dan [Detail] CROSS JOIN bekerja lebih baik daripada INNER JOIN.

RDBMS adalah Teradata dengan teknologi MPP-nya, dan IDR apa skema pengindeksannya. Tabel 7 baris tidak memiliki indeks karena TABLE SCAN selalu melakukan yang terbaik.

Timothy Oleary
sumber