Semua orang tahu bahwa pengembang baru menulis fungsi yang panjang. Ketika Anda maju, Anda menjadi lebih baik dalam memecahkan kode Anda menjadi potongan-potongan kecil dan pengalaman mengajarkan Anda nilai melakukannya.
Masukkan SQL. Ya, cara berpikir SQL tentang kode berbeda dengan cara berpikir prosedural tentang kode, tetapi prinsip ini tampaknya sama berlaku.
Katakanlah saya memiliki kueri yang berbentuk:
select * from subQuery1 inner join subQuerry2 left join subquerry3 left join join subQuery4
Menggunakan beberapa ID atau tanggal dll.
Subquery itu sendiri kompleks dan mungkin berisi subquery sendiri. Dalam konteks pemrograman lain saya tidak akan berpikir bahwa logika untuk subqueries 1-4 kompleks sesuai dengan permintaan orang tua saya yang bergabung dengan mereka semua. Tampaknya sangat mudah bahwa subqueries tersebut harus didefinisikan sebagai view, sama seperti mereka akan berfungsi jika saya menulis kode prosedural.
Jadi mengapa bukan praktik yang biasa? Mengapa orang begitu sering menulis query SQL monolitik panjang ini? Mengapa SQL tidak mendorong penggunaan tampilan yang luas seperti pemrograman prosedural mendorong penggunaan fungsi yang luas. (Dalam banyak lingkungan perusahaan, membuat tampilan bahkan bukan sesuatu yang mudah dilakukan. Ada permintaan dan persetujuan yang diperlukan. Bayangkan jika jenis programmer lain harus mengirimkan permintaan setiap kali mereka membuat fungsi!)
Saya telah memikirkan tiga kemungkinan jawaban:
Ini sudah umum dan saya bekerja dengan orang yang tidak berpengalaman
Pemrogram berpengalaman tidak menulis SQL kompleks karena mereka lebih suka menyelesaikan masalah pemrosesan data dengan kode prosedural
Sesuatu yang lain
Jawaban:
Saya pikir masalah utamanya adalah tidak semua database mendukung Common Table Expressions.
Majikan saya menggunakan DB / 2 untuk banyak hal. Versi terbaru mendukung CTE, sehingga saya dapat melakukan hal-hal seperti:
Hasilnya adalah bahwa kita dapat memiliki nama tabel / bidang yang sangat singkat dan pada dasarnya saya membuat tampilan temp, dengan nama yang lebih mudah dibaca, yang kemudian dapat saya gunakan. Tentu, kueri menjadi lebih lama. Tetapi hasilnya adalah saya bisa menulis sesuatu yang cukup jelas dipisahkan (menggunakan CTE seperti cara Anda menggunakan fungsi untuk mendapatkan KERING) dan berakhir dengan kode yang cukup terbaca. Dan karena saya dapat memecahkan subquery saya, dan memiliki satu referensi subquery lainnya, itu tidak semua "inline." Kadang-kadang saya telah menulis satu CTE, kemudian meminta empat CTE lain untuk semua referensi, lalu meminta kueri gabungan hasil dari empat terakhir.
Ini dapat dilakukan dengan:
Tapi berjalan jauh untuk membuat kode lebih bersih, lebih terbaca, lebih KERING.
Saya telah mengembangkan "pustaka standar" CTE yang dapat saya plug-in ke berbagai pertanyaan, membuat saya memulai dengan memulai permintaan baru saya. Beberapa dari mereka juga mulai dipeluk oleh para dev di organisasi saya.
Pada waktunya, mungkin masuk akal untuk mengubah beberapa dari ini menjadi pandangan, sehingga "pustaka standar" ini tersedia tanpa perlu menyalin / menempel. Tapi CTE saya akhirnya menjadi tweak, sedikit sekali, untuk berbagai kebutuhan yang saya tidak bisa memiliki CTE tunggal biasakan SO WIDELY, tanpa mod, yang mungkin layak membuat tampilan.
Tampaknya bagian dari keluhan Anda adalah "mengapa saya tidak tahu tentang CTE?" atau "mengapa DB saya tidak mendukung CTE?"
Adapun pembaruan ... ya, Anda dapat menggunakan CTE tetapi, dalam pengalaman saya, Anda harus menggunakannya di dalam klausa yang ditetapkan DAN di klausa mana. Akan lebih baik jika Anda bisa mendefinisikan satu atau lebih di depan seluruh pernyataan pembaruan dan kemudian hanya memiliki bagian "permintaan utama" di klausa set / di mana tetapi tidak berfungsi seperti itu. Dan tidak ada menghindari nama tabel / bidang tidak jelas pada tabel yang Anda perbarui.
Anda dapat menggunakan CTE untuk menghapus. Diperlukan beberapa CTE untuk menentukan nilai PK / FK untuk catatan yang ingin Anda hapus dari tabel itu. Sekali lagi, Anda tidak bisa menghindari nama tabel / bidang yang tidak jelas pada tabel yang Anda modifikasi.
Karena Anda dapat memilih ke dalam sisipan, Anda dapat menggunakan CTE untuk memasukkan. Seperti biasa, Anda mungkin berurusan dengan nama tabel / bidang tidak jelas pada tabel yang Anda modifikasi.
SQL TIDAK memungkinkan Anda membuat objek domain yang setara, membungkus tabel, dengan getter / setter. Untuk itu, Anda perlu menggunakan semacam ORM, bersama dengan bahasa pemrograman yang lebih prosedural / OO. Saya sudah menulis hal-hal semacam ini di Java / Hibernate.
sumber
Mengunci penciptaan tampilan database sering dilakukan oleh organisasi paranoid dari masalah kinerja dalam database. Ini adalah masalah budaya organisasi, bukan masalah teknis dengan SQL.
Lebih dari itu, query SQL monolitik besar ditulis berkali-kali, karena use case sangat spesifik sehingga sangat sedikit kode SQL yang dapat digunakan kembali dalam query lain. Jika permintaan yang kompleks diperlukan, biasanya untuk kasus penggunaan yang jauh berbeda. Menyalin SQL dari kueri lain sering kali merupakan titik awal, tetapi karena sub kueri dan GABUNGAN lain dalam kueri baru, Anda akhirnya memodifikasi SQL yang disalin cukup untuk memecahkan segala jenis abstraksi yang "fungsi" dalam bahasa lain akan lakukan. digunakan untuk. Yang membawa saya ke alasan paling penting mengapa SQL sulit untuk diperbaiki.
SQL hanya berurusan dengan struktur data konkret, bukan perilaku abstrak (atau abstraksi dalam arti kata). Karena SQL ditulis berdasarkan ide-ide konkret, tidak ada yang bisa diabstraksi menjadi modul yang dapat digunakan kembali. Tampilan database dapat membantu dengan ini, tetapi tidak pada tingkat yang sama dengan "fungsi" dalam bahasa lain. Tampilan basis data bukanlah abstraksi, melainkan kueri. Sebenarnya, tampilan basis data adalah kueri. Ini pada dasarnya digunakan seperti tabel, tetapi dieksekusi seperti sub kueri, jadi sekali lagi, Anda berurusan dengan sesuatu yang konkret, bukan abstrak.
Dengan abstraksi, kode menjadi lebih mudah direvisi, karena abstraksi menyembunyikan detail implementasi dari pengguna abstraksi itu. Straight SQL tidak memberikan pemisahan seperti itu, meskipun ekstensi prosedural ke SQL seperti PL / SQL untuk Oracle atau Transact-SQL untuk SQL Server mulai mengaburkan garis sedikit.
sumber
Hal yang saya pikir Anda mungkin hilang dari pertanyaan / sudut pandang Anda adalah bahwa SQL menjalankan operasi pada set (menggunakan operasi set dll.).
Ketika Anda beroperasi pada level itu, Anda tentu saja menyerahkan kontrol tertentu ke mesin. Anda masih dapat memaksakan beberapa kode gaya prosedural menggunakan kursor tetapi karena pengalaman menunjukkan 99/100 kali Anda seharusnya tidak melakukannya.
SQL Refactoring dimungkinkan tetapi tidak menggunakan prinsip kode refactoring yang sama seperti yang biasa kita gunakan dalam kode level aplikasi. Sebaliknya Anda mengoptimalkan cara Anda menggunakan mesin SQL itu sendiri.
Ini bisa dilakukan dengan berbagai cara. Jika Anda menggunakan Microsoft SQL Server, Anda dapat menggunakan SSMS untuk memberi Anda perkiraan rencana eksekusi dan Anda bisa menggunakannya untuk melihat langkah-langkah yang dapat Anda lakukan untuk menyempurnakan kode Anda.
Dalam kasus pemisahan kode menjadi modul-modul yang lebih kecil, seperti yang disebutkan @ greg-burghardt, SQL umumnya merupakan bagian kode yang dibuat khusus dan sebagai hasilnya. Itu melakukan satu hal yang perlu Anda lakukan dan tidak ada lagi. Itu mematuhi S dalam SOLID, hanya ada satu alasan untuk diubah / terpengaruh dan saat itulah Anda memerlukan permintaan itu untuk melakukan sesuatu yang lain. Sisa dari akronim (OLID) tidak berlaku di sini (AFAIK tidak ada injeksi dependensi, antarmuka atau dependensi seperti itu dalam SQL) tergantung pada rasa SQL yang Anda gunakan, Anda mungkin dapat memperluas pertanyaan tertentu dengan membungkusnya dalam fungsi prosedur / tabel tersimpan atau menggunakannya sebagai sub-kueri jadi, saya akan mengatakan prinsip buka-tutup akan tetap berlaku. Tapi saya ngelantur.
Saya pikir Anda perlu mengubah paradigma Anda dalam hal bagaimana Anda melihat kode SQL. Karena sifat set itu tidak dapat menyediakan banyak fitur yang dapat bahasa tingkat aplikasi (generik dll). SQL tidak pernah dirancang untuk menjadi seperti itu, itu adalah bahasa untuk permintaan set data, dan setiap set unik dengan caranya sendiri.
Yang sedang berkata, ada cara di mana Anda dapat membuat kode Anda terlihat lebih bagus, jika keterbacaan adalah prioritas tinggi dalam organisasi. Menyimpan bit dari blok SQL yang sering digunakan (kumpulan data umum yang Anda gunakan) ke fungsi nilai prosedur / tabel yang disimpan dan kemudian meminta dan menyimpannya dalam variabel tabel / tabel sementara, diikuti dengan menggunakannya untuk menggabungkan potongan-potongan tersebut menjadi satu transaksi besar. yang seharusnya Anda tulis adalah pilihan. IMHO tidak layak melakukan sesuatu seperti itu dengan SQL.
Sebagai bahasa itu dirancang agar mudah dibaca dan dimengerti oleh siapa pun, bahkan non-programmer. Dengan demikian, kecuali jika Anda melakukan sesuatu yang sangat pintar, tidak perlu mengubah kode SQL menjadi ukuran byte yang lebih kecil. Saya, secara pribadi, telah menulis query SQL yang sangat besar saat mengerjakan solusi data warehouse ETL / Reporting dan semuanya masih sangat jelas dalam hal apa yang sedang terjadi. Apa pun yang mungkin terlihat agak aneh bagi orang lain akan mendapatkan satu set komentar singkat di sampingnya untuk memberikan penjelasan singkat.
Saya harap ini membantu.
sumber
Saya akan fokus pada "subqueries" dalam contoh Anda.
Mengapa mereka begitu sering digunakan? Karena mereka menggunakan cara berpikir alami seseorang: Saya memiliki set data ini, dan ingin melakukan suatu tindakan pada subsetnya dan bergabung dengan subset data lainnya. 9 dari 10 kali saya melihat subquery, itu digunakan salah. Lelucon saya tentang subqueries adalah: orang yang takut bergabung menggunakan subqueries.
Jika Anda melihat subquery seperti itu, itu juga sering merupakan tanda desain database yang tidak optimal.
Semakin Normalisasi Basis Data Anda, semakin banyak yang Anda dapatkan, semakin banyak basis data Anda yang tampak seperti lembar excel besar, semakin banyak sub-pilihan yang Anda dapatkan.
Refactoring dalam SQL seringkali dengan tujuan yang berbeda: mendapatkan lebih banyak kinerja, waktu kueri yang lebih baik, "menghindari pemindaian tabel". Mereka bahkan dapat membuat kode kurang dibaca tetapi sangat berharga.
Jadi mengapa Anda melihat begitu banyak pertanyaan monolitik besar non-refactored?
(Bagi saya, semakin saya berpengalaman dengan SQL, semakin sedikit pertanyaan saya, SQL memiliki cara untuk orang-orang dari semua tingkat keterampilan untuk menyelesaikan pekerjaan mereka, apa pun yang terjadi.)
sumber
Pemisahan tugas
Dalam semangat SQL, database adalah aset bersama yang berisi data perusahaan, dan melindunginya sangat penting. Memasuki DBA sebagai penjaga kuil.
Membuat tampilan baru dalam database dipahami untuk melayani tujuan yang langgeng dan untuk dibagikan oleh komunitas pengguna. Dalam tampilan DBA, ini hanya dapat diterima jika tampilan dibenarkan oleh struktur data. Setiap perubahan tampilan kemudian dikaitkan dengan risiko untuk semua pengguna saat ini, bahkan mereka yang tidak menggunakan aplikasi tetapi yang telah menemukan tampilan. Akhirnya, pembuatan objek baru memerlukan otorisasi kelola, dan dalam kasus tampilan, secara konsisten dengan otorisasi tabel yang mendasarinya.
Semua ini menjelaskan mengapa DBA tidak suka menambahkan tampilan yang hanya untuk kode beberapa aplikasi individual.
Desain SQL
Jika Anda menguraikan salah satu kueri rumit yang bagus, Anda mungkin menemukan bahwa subquery akan sering memerlukan parameter yang bergantung pada subquery lain.
Jadi mentransformasikan subqueries dalam pandangan tidak harus sesederhana yang dinyatakan. Anda harus mengisolasi parameter variabel, dan merancang tampilan Anda sehingga parameter dapat ditambahkan sebagai kriteria pemilihan pada tampilan.
Sayangnya, saat melakukannya, Anda terkadang memaksakan untuk mengakses lebih banyak data dan kurang efektif daripada dalam kueri khusus.
Ekstensi kepemilikan
Anda bisa berharap beberapa refactoring, dengan mentransfer beberapa tanggung jawab ke ekstensi prosedural dari SQL, seperti PL / SQL atau T-SQL. Namun, ini tergantung vendor dan membuat ketergantungan teknologi. Selain itu, ekstensi ini dijalankan pada server database, menciptakan lebih banyak beban pemrosesan pada sumber daya yang jauh lebih sulit untuk diukur daripada server aplikasi.
Tapi apa masalahnya pada akhirnya?
Akhirnya, apakah pemisahan tugas dan desain SQL dengan kekuatan dan keterbatasannya merupakan masalah nyata? Pada akhirnya, basis data ini terbukti berhasil dan andal menangani data yang sangat kritis termasuk dalam lingkungan kritis misi.
Jadi untuk mencapai refactoring yang sukses:
pertimbangkan komunikasi yang lebih baik . Cobalah untuk memahami kendala DBA Anda. Jika Anda membuktikan kepada DBA bahwa pandangan baru dibenarkan oleh struktur data, bahwa itu bukan solusi membuang-pergi, dan bahwa itu tidak memiliki dampak keamanan, dia pasti akan setuju untuk membiarkannya dibuat. Karena, maka itu akan menjadi kepentingan bersama.
bersihkan rumah Anda sendiri terlebih dahulu : Tidak ada yang memaksa Anda untuk menghasilkan banyak SQL di banyak tempat. Perbaiki kode aplikasi Anda, untuk mengisolasi akses SQL, dan untuk membuat kelas atau fungsi untuk menyediakan subqueries yang dapat digunakan kembali, jika ini sering digunakan.
tingkatkan kesadaran tim : pastikan aplikasi Anda tidak melakukan tugas yang dapat dilakukan dengan lebih efisien oleh mesin DBMS. Seperti yang Anda tunjukkan dengan benar, pendekatan prosedural dan pendekatan berorientasi data tidak sama dikuasainya oleh anggota tim yang berbeda. Itu tergantung pada latar belakang mereka. Tetapi untuk mengoptimalkan sistem secara keseluruhan, tim Anda perlu memahaminya secara keseluruhan. Jadi ciptakan kesadaran, jadi untuk memastikan bahwa pemain yang kurang berpengalaman tidak menemukan kembali roda dan membagikan pemikiran DB mereka dengan anggota yang lebih berpengalaman.
sumber
Poin 1 & 3: Tampilan bukan satu-satunya cara. Ada juga tabel sementara, mart, variabel tabel, kolom teragregasi, CTE, fungsi, prosedur tersimpan dan kemungkinan konstruksi lainnya tergantung pada RDBMS.
DBA (dan saya berbicara sebagai seseorang yang telah menjadi DBA dan pengembang) cenderung memandang dunia dengan cara yang sangat biner sehingga seringkali menentang hal-hal seperti pandangan dan fungsi karena penalti kinerja yang dirasakan.
Akhir-akhir ini, kebutuhan untuk bergabung kompleks telah berkurang dengan pengakuan bahwa tabel yang dinormalisasi meskipun sub-optimal dari sudut pandang NF , sangat berkinerja tinggi.
Ada juga tren untuk melakukan kueri sisi klien dengan teknologi seperti LINQ yang Anda tingkatkan di poin 2.
Sementara saya setuju bahwa SQL dapat menantang untuk modularise, langkah besar telah dibuat walaupun akan selalu ada dikotomi antara kode sisi klien dan SQL - meskipun 4GL telah mengaburkan garis.
Saya kira itu benar-benar tergantung pada seberapa jauh DBA / arsitek / lead teknologi Anda bersedia untuk menyerah dalam hal ini. Jika mereka menolak untuk mengizinkan apa pun selain vanilla SQL dengan banyak gabungan, pertanyaan besar dapat terjadi. Jika Anda terjebak dengan ini, jangan membenturkan kepala Anda ke dinding bata, tingkatkan itu. Biasanya ada cara yang lebih baik dalam melakukan sesuatu dengan sedikit kompromi - terutama jika Anda dapat membuktikan manfaatnya.
sumber