Apakah SQL deklaratif?

22

Saya bertanya karena begitu banyak pertanyaan yang saya lihat dalam jumlah SQL untuk: "Ini lambat. Bagaimana saya mempercepatnya"? Atau apakah tutorial menyatakan "Lakukan ini dengan cara ini dan jangan seperti itu karena lebih cepat".

Tampak bagi saya bahwa sebagian besar dari SQL mengetahui bagaimana ekspresi akan dilakukan dan dari pengetahuan itu memilih gaya ekspresi yang berkinerja lebih baik. Ini tidak sesuai dengan satu aspek pemrograman deklaritif - yaitu meninggalkan sistem untuk memutuskan cara terbaik untuk melakukan perhitungan dengan Anda hanya menentukan apa yang harus dihasilkan perhitungan.

Bukankah seharusnya mesin SQL tidak peduli jika Anda menggunakan in, existsatau joinjika itu benar-benar deklaratif tidak hanya memberi Anda jawaban yang benar dalam waktu yang wajar jika memungkinkan dengan salah satu dari tiga metode ini? Contoh terakhir ini diminta oleh posting terbaru ini yang merupakan jenis yang disebutkan dalam paragraf pembuka saya.

Indeks

Saya kira contoh termudah yang bisa saya gunakan terkait dengan membuat indeks untuk tabel. Gumph di sini di w3schools.com bahkan mencoba menjelaskannya sebagai sesuatu yang tidak terlihat oleh pengguna yang ada karena alasan kinerja. Deskripsi mereka tampaknya menempatkan indeks SQL di kamp non-deklaratif dan mereka secara rutin ditambahkan dengan tangan karena alasan murni kinerja.

Apakah ini kasus mereka di suatu tempat yang ideal SQL DB yang jauh lebih deklaratif daripada yang lain tetapi karena itu yang baik tidak mendengar tentang hal itu?

Paddy3118
sumber
@FrustratedWithFormsDesigner: Saya tahu persis apa artinya itu. select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param). Itu harus sepele untuk melihat bagaimana menyatakan kembali itu dengan existsatau join.
Mason Wheeler
Dengan menggunakan alasan yang sama, saya kira ekspresi reguler adalah metode ekspresi yang lebih deklaratif karena saya jarang melihat pertanyaan kinerja dijawab oleh "Anda harus menuliskannya dengan cara ini untuk mendapatkan kinerja yang lebih baik". Saya mengacaukan otak saya dan setengah dapat mengingat beberapa pertanyaan yang berkaitan dengan pandangan negatif di belakang atau di depan dalam regexp lambat di mana jawabannya adalah menulis ulang regexp dengan cara berbeda untuk melakukan hal yang sama dalam waktu yang lebih singkat.
Paddy3118
Kinerja adalah detail implementasi. Kinerja hampir semua implementasi IN dapat dibandingkan atau lebih baik dari EXIS dan JOIN jika pengembang prosesor kueri merasa itu adalah prioritas.
JustinC
1
@ JustinC, sepertinya lebih dari detail mengingat banyaknya pertanyaan dan tips SQL yang berorientasi kinerja untuk bahasa yang seharusnya deklaratif?
Paddy3118
Tidak ada definisi yang jelas tentang bahasa pemrograman deklaratif, sehingga tidak ada artinya untuk dibicarakan. Beberapa bahasa memiliki level yang lebih tinggi daripada yang lain, itu saja.
Gardenhead

Jawaban:

21

SQL secara teoritis bersifat deklaratif. Tapi Anda tahu apa yang mereka katakan tentang perbedaan antara teori dan praktek ...

Pada intinya, konsep "pemrograman deklaratif" tidak pernah benar-benar efektif, dan kemungkinan tidak akan pernah sampai kita memiliki kompiler berbasis AI yang mampu melihat kode dan menjawab pertanyaan "apa tujuan dari kode ini?" secara cerdas, dengan cara yang sama seperti orang yang menulisnya. Inti dari setiap bahasa deklaratif adalah sejumlah besar kode imperatif yang berusaha dengan panik memecahkan masalah itu tanpa bantuan AI.

Seringkali ini bekerja dengan sangat baik, karena kasus yang paling umum adalah kasus yang umum , yang diketahui orang-orang yang menulis implementasi bahasa dan menemukan cara yang baik untuk mengatasinya. Tetapi kemudian Anda menghadapi kasus tepi yang tidak dipertimbangkan oleh implementor, dan Anda melihat kinerja menurun dengan cepat karena penerjemah dipaksa untuk mengambil kode secara lebih harfiah dan menanganinya dengan cara yang kurang efisien.

Mason Wheeler
sumber
3
Tidak pernah benar-benar efektif? SQL, LINQ, Knockout.js, Prolog, bahasa ELM. Anda mungkin ingin memeriksa lagi. Saya menggunakan sebagian besar teknologi deklaratif saat ini.
brian
5
@ Brian: Dan semuanya merosot dengan cepat ketika Anda menemukan kasing tepi yang tidak dipikirkan oleh siapa pun. Saya kira saya seharusnya mengatakan "tidak pernah benar-benar efektif dalam kasus umum ."
Mason Wheeler
Kapan balasan Anda diatur untuk menurunkan melihat bagaimana itu disimpan dalam database SQL Server? :) Saya jarang menemukan kasus tepi di salah satu dari mereka yang tidak dapat diselesaikan dalam kerangka kerja. Saya melihat dari mana Anda berasal tetapi kasus tepi benar-benar tidak membuat saya kesakitan karena betapa bermanfaat dan mudahnya alasan sekitar 99% dari kode deklaratif. Ini seperti mengatakan Clojure atau F # itu buruk karena Anda harus menggunakan tipe yang bisa berubah untuk menyelesaikan masalah Anda.
brian
11
@ Brian: I rarely hit an edge case in any of them that couldn't be solved within the framework.Ya, itulah intinya: harus mencari cara untuk menyelesaikannya dalam kerangka karena kerangka tidak cukup pintar untuk menyelesaikannya untuk Anda seperti cara Anda menyatakannya.
Mason Wheeler
Bagaimana dengan pilih ... untuk pembaruan? Tampaknya perintah penting.
Jesvin Jose
6

Saya memikirkan ini beberapa hari yang lalu setelah optimasi SQL. Saya pikir kita bisa sepakat bahwa SQL adalah "bahasa deklaratif" dalam definisi Wikipedia:

Pemrograman paradigma yang mengekspresikan logika perhitungan tanpa menjelaskan aliran kontrolnya

Jika Anda berpikir berapa banyak hal yang dilakukan di balik tirai (melihat statistik, memutuskan apakah indeks berguna, mencari bergabung, bergabung atau hash bergabung, dll. Dll.) Kita harus mengakui bahwa kita hanya memberikan tingkat tinggi logika, dan database menangani semua logika aliran kontrol level rendah.

Juga dalam skenario ini, kadang-kadang pengoptimal database membutuhkan beberapa "petunjuk" dari pengguna untuk memberikan hasil terbaik.

Definisi umum lain dari bahasa "deklaratif" adalah (saya tidak dapat menemukan sumber otoritatif):

Pemrograman paradigma yang mengekspresikan hasil perhitungan yang diinginkan tanpa menjelaskan langkah-langkah untuk mencapainya (juga disingkat dengan "menggambarkan apa, bukan bagaimana")

Jika kami menerima definisi ini, kami menghadapi masalah yang dijelaskan oleh OP.

Masalah pertama adalah bahwa SQL memberi kita beberapa cara yang setara untuk mendefinisikan "hasil yang sama". Mungkin itu adalah kejahatan yang diperlukan: semakin banyak kekuatan ekspresif yang kita berikan pada suatu bahasa, semakin besar kemungkinannya memiliki cara berbeda untuk mengekspresikan hal yang sama.

Sebagai contoh, saya pernah diminta untuk mengoptimalkan kueri ini:

 SELECT Distinct CT.cust_type,  ct.cust_type_description 
   from customer c 
              INNER JOIN 
              Customer_type CT on c.cust_type=ct.cust_type;

Karena jenisnya jauh lebih sedikit daripada pelanggan dan ada indeks di cust_typeatas meja pelanggan, saya telah mencapai peningkatan besar dengan menulis ulang sebagai:

 SELECT CT.cust_type,  ct.cust_type_description 
   from Customer_type CT
  Where exists ( select 1 from customer c 
                  Where c.cust_type=ct.cust_type);

Dalam kasus khusus ini, ketika saya bertanya kepada pengembang apa yang ingin dia capai, dia mengatakan kepada saya, "Saya ingin semua jenis pelanggan yang saya miliki setidaknya satu pelanggan", yang kebetulan persis seperti yang dijelaskan oleh kueri pengoptimal.

Jadi, jika saya dapat menemukan kueri yang setara dan lebih efisien, mengapa pengoptimal tidak dapat melakukan hal yang sama?

Tebakan terbaik saya adalah karena dua alasan utama:

SQL mengungkapkan logika:

karena SQL mengekspresikan logika tingkat tinggi, apakah kita benar-benar ingin pengoptimal untuk "mengakali" kita dan logika kita? Saya akan dengan antusias meneriakkan "ya" jika bukan karena berkali-kali saya harus memaksa pengoptimal memilih jalur eksekusi paling efisien. Saya pikir idenya mungkin untuk memungkinkan pengoptimal untuk melakukan yang terbaik (juga merevisi logika kami) tetapi memberi kami "mekanisme petunjuk" untuk datang ke penyelamatan ketika sesuatu menjadi gila (itu akan seperti memiliki roda + rem di sebuah mobil otonom).

Lebih banyak pilihan = lebih banyak waktu

Bahkan pengoptimal RDBMS terbaik tidak menguji SEMUA jalur eksekusi yang mungkin, karena mereka harus sangat cepat: seberapa bagus untuk mengoptimalkan kueri dari 100 ms hingga 10 ms jika saya perlu menghabiskan setiap waktu 100 ms untuk memilih jalur terbaik? Dan itu dengan optimizer yang menghormati "logika tingkat tinggi" kami. Jika juga harus menguji semua kueri SQL yang setara, waktu pengoptimal dapat tumbuh beberapa kali.

Contoh bagus lain dari permintaan menulis ulang yang tidak dapat dilakukan RDBMS adalah (dari posting blog yang menarik ini )

SELECT t1.id, t1.value, SUM(t2.value)
  FROM mytable t1
       JOIN mytable t2
         ON t2.id <= t1.id
 GROUP BY t1.id, t1.value;

daripada yang dapat ditulis sebagai ini (Fungsi analitis diperlukan)

 SELECT id, value, SUM(t1.value) OVER (ORDER BY id)
   FROM mytable
Insac
sumber
1
Contoh penulisan ulang join menjadi ada menarik. Satu aturan praktis yang saya coba untuk mengesankan pada pengembang SQL adalah bahwa penggunaan DISTINCT adalah bau kode - baik permintaan, atau model data, sangat mungkin salah, dan pendekatan yang berbeda harus dicari.
David Aldridge