SQLは宣言的ですか?


22

私が尋ねるのは、SQLで見られる質問の多くが「これは遅いです。どうすれば高速化できますか」ということです。または、「この方法を使用し、高速ではないので、この方法を使用してください」と記載されているチュートリアルです。

SQLの大部分は、式がどのように実行されるかを知っており、その知識から、より良いパフォーマンスの式スタイルを選択しているように思えます。これは、宣言型プログラミングの1つの側面(システムが計算を生成する対象を指定するだけで計算を実行する最適な方法を決定することを離れる)とは異なります。

SQLエンジンは、を使用inしたexistsjoinどうかを気にしてはいけませんか、それが本当に宣言型である場合、3つの方法のいずれかによって可能であれば、妥当な時間内に正しい答えを与えるべきではありませんか?この最後の例は、冒頭の段落で言及したタイプのこの最近の投稿によって促されます。

インデックス

私が使用できた最も簡単な例は、テーブルのインデックスの作成に関するものだと思います。gumph w3schools.com上、ここでは、でも、パフォーマンス上の理由であり、ユーザが目に見えない何かとしてそれを説明しようとします。それらの記述は、SQLインデックスを非宣言型のキャンプに入れているようで、純粋にパフォーマンス上の理由で手作業で定期的に追加されています。

彼らはどこか他のすべてよりもはるかに宣言的な理想的なSQL DBですが、それは良い人がそれについて聞いていないためですか?


@FrustratedWithFormsDesigner:それが何を意味するのか正確に知っています。 select whatever from sometable where FKValue in (select FKValue from sometable_2 where other_value = :param)。とのことを修正再表示する方法を確認するのは簡単であるべきexistsjoin
メイソンウィーラー

同様の推論を使用すると、「より良いパフォーマンスを得るためにこのように書くべきです」というパフォーマンスの質問に答えることはめったにないので、正規表現はより宣言的な表現方法だと思います。私は頭を悩ませていますが、遅い正規表現でネガティブな後読みや先読みに関係する質問を半分思い出すことができます。
Paddy3118

パフォーマンスは実装の詳細です。ほとんどすべてのIN実装のパフォーマンスは、クエリプロセッサ開発者がそれが優先事項であると感じた場合、EXISTSおよびJOINと同等またはそれ以上になる可能性があります。
JustinC

1
@JustinC、パフォーマンス指向のSQL質問と宣言的言語のヒントの圧倒的多数を考えると、それは詳細以上のものであるように思われますか?
Paddy3118

宣言型プログラミング言語の明確な定義はないので、話すことは無意味です。一部の言語は他の言語よりも高レベルです。それだけです。
ガーデンヘッド

回答:


21

SQLは理論的に宣言的です。しかし、あなたは彼らが理論と実践の違いについて言うことを知っています...

本質的に、「宣言型プログラミング」の概念は真に効果的ではなく、コードを見て、「このコードの意図は何ですか?」という質問に答えることができるAIベースのコンパイラーができるまでは決して実現しません。知的に、それを書いた人がそうするのと同じように。すべての宣言型言語の中心にあるのは、AIの助けを借りずにその問題を必死に解決しようとする一連の命令型コードです。

最も一般的なケースは一般的なケースであるため、多くの場合、驚くほどうまく機能します。これは、言語の実装を作成した人々が適切な処理方法を知っており、見つけたためです。しかし、その後、実装者が考慮しなかったエッジケースにぶつかり、インタープリターがコードを文字通りもっと効率的に処理しなければならないため、パフォーマンスが急速に低下することがわかります。


3
本当に効果的ではありませんか?SQL、LINQ、Knockout.js、Prolog、ELM言語。もう一度確認してください。私は現在、ほとんど宣言型の技術を使用しています。
ブライアン

5
@brian:誰も考えもしなかったエッジケースが発生すると、それらはすべて急速に劣化します。「一般的なケースでは本当に効果的ではない」と言うべきだったと思います。
メイソンウィーラー

返信は、SQL Serverデータベースにどのように保存されていると見なされて低下するように設定されていますか?:)フレームワーク内で解決できなかったエッジケースはほとんどありません。あなたがどこから来たのかはわかりますが、エッジケースは本当に宣言的なコードの約99%が有益で推論しやすいのであまり痛みを引き起こしません。問題を解決するために可変タイプを使用しなければならなかったため、ClojureまたはF#が悪いと言っているようなものです。
ブライアン

11
@brian:I rarely hit an edge case in any of them that couldn't be solved within the framework.ええ、それが全体のポイントです。フレームワーク内でそれらを解決する方法を見つけ出す必要があります。フレームワークは、最初に宣言した方法でそれを解決するほどスマートではないからです。
メイソンウィーラー

select ...更新についてはどうですか?これは必須のコマンドのようです。
ジェスビン・ホセ

6

私はこれを数日前にSQL最適化の後に考えていました。SQLはウィキペディアの定義における「宣言型言語」であることに同意できると思います。

制御フローを記述せずに計算のロジックを表現するプログラミングパラダイム

カーテンの後ろで何が行われるかを考える場合(統計を見て、インデックスが有用かどうかを判断し、ネスト、マージ、またはハッシュ結合などに進む)など、高レベルを与えることを認める必要があります。ロジック、およびデータベースがすべての低レベル制御フローロジックを処理しました。

また、このシナリオでは、最良の結果を得るために、データベースオプティマイザーがユーザーからの「ヒント」を必要とする場合があります。

「宣言的」言語のもう1つの一般的な定義は次のとおりです(正式なソースが見つかりません)。

計算の目的の結果を、それを達成するための手順を説明せずに表現するプログラミングパラダイム

この定義を受け入れると、OPで説明されている問題が発生します。

最初の問題は、SQLが「同じ結果」を定義するための複数の同等の方法を提供することです。おそらくそれは必要な悪です。言語に表現力を与えるほど、同じものを表現するさまざまな方法がある可能性が高くなります。

例として、このクエリを最適化するように一度求められました。

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

タイプは顧客よりもはるかに少なく、cust_typeon customerテーブルにインデックスがあったため、次のように書き直すことで大きな改善を達成しました。

 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);

この特定のケースでは、開発者に何を達成したいかを尋ねると、「少なくとも1人の顧客がいるすべての顧客タイプが欲しい」と言われましたが、それは偶然にもオプティマイザークエリの記述方法です。

それで、同等でより効率的なクエリを見つけることができた場合、オプティマイザーで同じことができないのはなぜですか?

私の最良の推測は、主に次の2つの理由によるものです。

SQLはロジックを表現します:

SQLは高レベルのロジックを表現するため、オプティマイザーが私たちと私たちのロジックを「裏切る」ことを本当に望んでいますか?オプティマイザーが最も効率的な実行パスを選択するように強制する必要が常になかった場合、私は熱心に「はい」と叫ぶでしょう。オプティマイザが最善を尽くす(ロジックの修正も可能)が、何かがおかしくなったときに救助に来る「ヒントメカニズム」を提供することだと思います(ホイール+ブレーキを入れるようなものです)自動運転車)。

より多くの選択肢=より多くの時間

最高のRDBMSオプティマイザーでさえ、可能な限りすべての実行パスをテストするわけではありません。それらは本当に高速でなければならないためです。そして、それはオプティマイザーが「高レベルのロジック」を尊重していることです。同等のSQLクエリもすべてテストする必要がある場合、オプティマイザーの時間は複数回長くなる可能性があります。

no RDBMSが実際に実行できるクエリ書き換えの別の良い例は(この興味深いブログ投稿から)です

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;

このように書くことができる(分析関数が必要)

 SELECT id, value, SUM(t1.value) OVER (ORDER BY id)
   FROM mytable

1
存在への結合を書き換える例は興味深いです。私がSQL開発者に印象付けようとする経験則の1つは、DISTINCTの使用はコードのにおいであるということです。クエリまたはデータモデルのいずれかが非常に間違っている可能性があり、別のアプローチを探す必要があります。
デビッドアルドリッジ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.