Apakah lebih baik untuk memisahkan kueri besar menjadi beberapa kueri yang lebih kecil?


13

Ada situasi yang mengharuskan memiliki kueri sangat besar bergabung dengan beberapa tabel bersama dengan pernyataan sub pilih di dalamnya untuk menghasilkan hasil yang diinginkan.

Pertanyaan saya adalah, haruskah kita mempertimbangkan menggunakan beberapa kueri yang lebih kecil dan membawa operasi logis ke dalam lapisan aplikasi dengan meminta DB dalam lebih dari satu panggilan atau lebih baik memiliki semuanya sekaligus?
Sebagai contoh, pertimbangkan pertanyaan berikut:

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY RAND() 
LIMIT %2$d

Apa cara terbaik untuk melakukannya?

Jawaban:


14

Saya akan tidak setuju pada pertanyaan besar dan rumit dengan datagod di sini. Saya melihat ini hanya sebagai masalah jika mereka tidak terorganisir. Dari segi kinerja, ini hampir selalu lebih baik karena perencana memiliki lebih banyak kebebasan dalam cara mencari informasi. Namun, pertanyaan besar memang perlu ditulis dengan pemikiran rawatan. Secara umum, saya telah menemukan bahwa SQL yang sederhana dan terstruktur dengan baik agar mudah di-debug bahkan ketika satu query berjalan untuk lebih dari 200 baris. Ini karena biasanya Anda memiliki ide yang cukup bagus tentang masalah apa yang Anda hadapi sehingga hanya ada beberapa area dalam kueri yang harus Anda periksa.

Masalah pemeliharaan, IME, datang ketika struktur SQL rusak. Kueri yang panjang dan kompleks di dalam sub-selektif merusak keterbacaan dan pemecahan masalah, seperti halnya tampilan inline, dan keduanya harus dihindari dalam kueri panjang. Sebagai gantinya, gunakan LIHAT jika Anda bisa (perhatikan jika Anda menggunakan MySQL, tampilan tidak melakukan semua itu dengan baik, tetapi pada sebagian besar db lainnya,), dan gunakan ekspresi tabel umum di mana itu tidak berfungsi (MySQL tidak mendukung ini btw).

Pertanyaan kompleks yang panjang bekerja dengan baik baik dari kasus rawatan dan kinerja di mana Anda menjaga klausa tempat Anda tetap sederhana, dan di mana Anda melakukan sebanyak yang Anda bisa dengan bergabung, bukan dengan subseleksi. Tujuannya adalah untuk membuatnya sehingga "catatan tidak muncul" memberi Anda beberapa tempat yang sangat spesifik dalam kueri untuk diperiksa (apakah dijatuhkan dalam gabungan atau disaring dalam klausa mana?) Dan tim pemeliharaan sebenarnya dapat mempertahankan hal-hal.

Mengenai skalabilitas, ingatlah bahwa semakin banyak fleksibilitas yang dimiliki perencana, itu hal yang baik juga ....

Sunting: Anda menyebutkan ini adalah MySQL, sehingga tampilan tidak mungkin berkinerja baik dan CTE tidak ada pertanyaan. Selain itu contoh yang diberikan tidak terlalu panjang atau rumit sehingga tidak ada masalah.


Catatan: Saya punya pertanyaan (bukan di MySQL, tapi masih ...) yang cukup panjang dan kompleks sehingga rencana kueri yang dihasilkan tidak optimal. Dalam kasus ini, Anda memang bisa mendapatkan hasil yang lebih cepat dengan memecah satu kueri yang sangat kompleks menjadi dua kueri yang kurang kompleks. Yang mengatakan, itu jarang, dan saya biasanya akan menulis kueri yang kompleks dan mencari tahu apakah ada masalah daripada memecah kueri menjadi potongan yang lebih kecil secara pre-emptively.
RDFozz

8

Sebagai seseorang yang harus mendukung / membersihkan pertanyaan besar dan rumit ini, saya akan mengatakan itu jauh lebih baik untuk memecah mereka menjadi beberapa potongan kecil yang mudah dimengerti. Ini tidak selalu lebih baik dari sudut pandang kinerja, tetapi Anda setidaknya memberikan SQL kesempatan yang lebih baik untuk datang dengan rencana permintaan yang bagus.

Buat hidup lebih mudah pada orang-orang yang mengikuti Anda, dan mereka akan mengatakan hal-hal baik tentang Anda. Buat itu sulit bagi mereka dan mereka akan mengutuk Anda.


2
Kerugian dari serangkaian pertanyaan sederhana adalah bahwa keadaan berubah secara signifikan di atasnya, membuat debugging keseluruhan aplikasi lebih kompleks. Yaitu Anda dapat men-debug permintaan SQL besar sering sebagai pohon tetapi kode aplikasi mendapat pernyataan debug oleh pernyataan memeriksa bagaimana perubahan negara dalam pernyataan. Masalah sebenarnya ada hubungannya dengan fakta bahwa subselect dan inline view juga pohon mereka sendiri .....
Chris Travers

Dalam kasus saya, satu-satunya yang harus mengelola DB dan kode adalah saya sendiri. Dan sebagian besar pertanyaan saya adalah tentang kinerja titik permintaan.
Hamed Momeni

Kalian harus melihat cara saya menulis proses batch besar saya. Hancurkan beberapa hal menjadi pertanyaan sederhana, sangat mudah dibaca. Saya bias karena pertanyaan saya akhirnya mencoba merapikan secara rutin lebih dari 1000 baris.
datagod

5

2 sen saya pada 2 kata kunci, performa dan skalabilitas kata kunci:

Query-Performance: Paralelisme SQL Server sudah melakukan pekerjaan yang sangat baik memecah query menjadi pencarian multi-threaded jadi saya tidak yakin berapa banyak peningkatan kinerja query yang akan Anda lihat dengan melakukannya untuk SQL Server. Anda harus melihat pada rencana eksekusi untuk melihat seberapa jauh tingkat paralelisme yang Anda dapatkan ketika Anda menjalankannya dan membandingkan hasil keduanya. Jika Anda akhirnya harus menggunakan petunjuk kueri untuk mendapatkan kinerja yang sama atau lebih baik, maka IMO tidak layak karena petunjuk kueri mungkin tidak akan optimal nanti.

Skalabilitas: Membaca kueri mungkin lebih mudah seperti yang dinyatakan datagod, dan memecahnya menjadi kueri yang terpisah masuk akal jika Anda dapat menggunakan kueri baru di area lain juga, tetapi jika Anda tidak akan menggunakannya untuk panggilan lain juga, maka itu akan menjadi procs yang lebih disimpan untuk mengelola untuk 1 tugas, dan IMO tidak akan berkontribusi pada skalabilitas.


2
RE: "SQL Server" referensi meskipun OP belum menentukan RDBMS tertentu saya menduga mereka di MySQL dari kutu belakang danLIMIT
Martin Smith

@ MartinSmith Anda mencurigai dengan benar. Itu adalah MySQL.
Hamed Momeni

2

Terkadang, tidak ada pilihan selain untuk memecah kueri besar / kompleks menjadi kueri kecil. Cara terbaik untuk menentukan itu adalah dengan menggunakan EXPLAINpernyataan dengan SELECTpernyataan itu. Jumlah jejak / pindaian yang akan dilakukan db Anda untuk mengambil data Anda adalah produk dari nilai "baris" yang dikembalikan oleh EXPLAINkueri Anda . Dalam kasus kami, kami memiliki kueri yang menggabungkan 10 tabel. Untuk catatan tertentu, jejak berjumlah 409M yang membuat blog DB kami dan mendorong penggunaan CPU kami dari server DB kami lebih dari 300%. Kami dapat mengambil informasi yang sama dengan memecah kueri jauh lebih cepat.

Jadi, singkatnya, dalam beberapa kasus memecah permintaan yang kompleks / besar masuk akal tetapi dalam kasus lain hal itu dapat menyebabkan banyak masalah kinerja atau pemeliharaan dan ini harus diperlakukan berdasarkan kasus per kasus.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.