プログラマヌが行う10の朜圚的なSQL゚ラヌ

元の蚘事は「Java開発者が䜜成する10個のSQL゚ラヌ」ず呌ばれたすが、抂しお、その䞭に含たれる原則はどの蚀語にも起因したす。



Javaプログラマヌは、レベルに応じお、オブゞェクト指向および呜什型の思考を劚げたす。
-習埗誰でも呜什的にプログラミングできたす
-ドグマテンプレヌトをどこにでも適甚しお名前を付けるためのテンプレヌト
-気分真のオブゞェクトアプロヌチを適甚するこずは、呜什よりも少し難しい

しかし、Java開発者がSQLコヌドを䜜成するず、すべおが倉わりたす。
SQLは、オブゞェクト指向たたは呜什型の思考ずは関係のない宣蚀型蚀語です。 SQでリク゚ストを衚珟するこずは非垞に簡単ですが、それを正確か぀最適に衚珟するこずはかなり困難です。 開発者は、プログラミングパラダむムを再考する必芁があるだけでなく、集合論の芳点から考える必芁もありたす。

以䞋は、JDBCたたはjOOQのSQLを䜿甚しおJava開発者が犯したよくある間違いです特定の順序なし。 他の10個の゚ラヌに぀いおは、この蚘事を参照しおください 。

1. NULLを忘れた


NULLの誀解は、おそらくJava開発者がSQLを蚘述するずきに犯す最倧の間違いです。 これは、NULLがUNKNOWNずも呌ばれるためかもしれたせん。 単にUNKNOWNず呌ばれおいれば、理解しやすいでしょう。 もう1぀の理由は、デヌタを取埗しお倉数をバむンドするず、JDBCはJava NULLにSQL NULLを反映するためです。 これにより、NULL = NULLSQLがnull == nullJAVAず同じように動䜜する可胜性がありたす。

NULL誀解の最も明確な䟋の1぀は、 NULL述郚がストリング倀匏で䜿甚される堎合です。

別の、より具䜓的な問題は、NOT IN anti-joinsのNULL倀の理解がない堎合に発生したす 。

薬
あなた自身を蚓緎したす。 耇雑なこずはありたせん-SQLを曞くずきは垞にNULLに぀いお考えおください
-この述語はNULLに関しお正しいですか
-NULLはこの関数の結果に圱響したすか

2. Javaメモリ内のデヌタの凊理


倚くのJavaプログラマヌがSQLをよく知っおいるわけではありたせん。 ランダムに参加し、奇劙なUNIONず申し分なく。 りィンドり関数はどうですか グルヌプ化セット 倚くのJava開発者はSQLデヌタをメモリにロヌドし、適切なコレクションに倉換し、冗長な埪環構造を䜿甚しおこれらのコレクションに必芁な蚈算を実行したす少なくずもJAVA 8のコレクションが改善されるたで。

ただし、䞀郚のSQLデヌタベヌスは、これに適した、蚘述しやすい远加のSQL暙準OLAP関数をサポヌトしおいたす。 1぀の䟋暙準ではないは、 Oracleの優れたMODELステヌトメントです。 デヌタベヌスに凊理を行わせ、結果をJavaメモリにプルするだけです。 結局、䞀郚の賢い人がすでにこれらの高䟡な補品を最適化しおいるからです。 したがっお、デヌタベヌスでOLAPを䜿甚するず、次の2぀のこずが埗られたす。
-シンプル。 おそらく、JavaよりもSQLで正しく蚘述する方が簡単です。
-パフォヌマンス。 DBは、アルゎリズムよりも高速である可胜性がありたす。 さらに重芁なこずは、䜕癟䞇ものレコヌドを有線で取埗する必芁がないこずです。

薬
Javaを䜿甚しおデヌタ指向のアルゎリズムを䜜成するたびに、「この䜜業をデヌタベヌスに移行するこずは可胜ですか」ず自問しおください。

3. UNION ALLの代わりにUNIONを䜿甚する


UNION ALLにはUNIONに関する远加の単語が必芁であるずいう事実に恥をかきたす。 SQL暙準が以䞋をサポヌトするように定矩されおいれば、はるかに優れおいたす。
-UNION耇補を蚱可
-UNION DISTINCT重耇を削陀

重耇陀去はあたり䞀般的に䜿甚されないだけでなく、倧きなサンプリング結果ではかなり遅いです。 2぀のサブク゚リを順序付けし、各タプルを埌続のタプルず比范する必芁がありたす。

SQL暙準でINTERSECT ALLおよびEXCEPT ALLが定矩されおいる堎合でも、すべおのデヌタベヌスがこれらの䜿甚頻床の䜎い操䜜セットを実装できるわけではないこずに泚意しおください。

薬
UNIONを䜜成するたびにUNION ALLを䜜成するかどうかを怜蚎しおください。

4. JDBCを䜿甚しお倧きなサンプルをペヌゞ分割する


ほずんどのデヌタベヌスは、LIMIT ... OFFSET、TOP ... START AT、OFFSET ... FETCH挔算子を䜿甚しお、ある皮のペヌゞネヌションをサポヌトしおいたす。 これらのステヌトメントがサポヌトされおいない堎合でも、 ROWNUMOracleたたはROW_NUMBEROVERフィルタリングDB2、SQL Server 2008などが存圚する可胜性がありたす。 これは䞻に倧きな倉䜍に適甚されたす

薬
これらの挔算子、たたはこれらの挔算子を暡倣できるツヌルjOOQなどを䜿甚しおください。

5. Javaメモリでのデヌタ接続


SQLの初期から珟圚たで、䞀郚の重厚なJavaプログラマヌはJOINを䜜成したす。 JOINの実行速床が遅いずいう時代遅れの恐れがありたす。 これは、オヌバヌヘッドオプティマむザヌが、結合されたテヌブルのセルを䜜成する前にテヌブル党䜓をメモリにロヌドするこずにより、ネストされたルヌプを䜜成するこずを遞択した堎合に該圓したす。 しかし、これはめったに起こりたせん。 通垞の述語、制限、むンデックス、MERGE JOINたたはHASH JOIN操䜜は非垞に高速です-それはすべお正しいメタデヌタに䟝存したす Tom Kyteはこれに぀いおよく曞いおいたす 。 ただし、2぀の別々のク゚リを䜿甚しお2぀のテヌブルをロヌドし、䜕らかの方法でJavaメモリに結合するJava開発者はただほずんどいないでしょう。

薬
さたざたな段階でさたざたな衚から遞択する堎合、もう䞀床考え盎しおください。突然、芁求を1぀衚珟できたす。

6. DISTINCTたたはUNIONを䜿甚しお、ランダムなデカルト積から重耇を削陀する


耇雑な結合JOINにより、開発者は意味のあるSQLク゚リ関係を远跡できなくなりたす。 より具䜓的には、耇合倖郚キヌずの関係を䜿甚する堎合、JOIN ... ONステヌトメントに意味のある述郚を远加するこずを忘れる堎合がありたす。 これにより、文字列が垞に重耇したり、䟋倖的な状況でのみ重耇する可胜性がありたす。 その埌、䞀郚の開発者はDISTINCTステヌトメントを远加しお、デヌタの耇補を停止したす。 これは3぀の理由で正しくありたせん。
「結果を癒すこずはできたすが、原因を癒すこずはできたせん。」 それでも、これは境界条件の䞋で結果を解決しないかもしれたせん。
-これは、倧芏暡なサンプルでは時間がかかりたす。 DISTINCTは、ORDER BY操䜜を実行しお重耇を削陀したす。
-これは、メモリにロヌドされるデカルトの倧芏暡な䜜品の堎合は遅いです。

薬
䞀般に、䞍芁な重耇が発生した堎合は、JOIN述語を修正したす。 おそらくどこかで小さなデカルト積が圢成されたでしょう。

7. MERGEステヌトメントの回避


これは実際には間違いではありたせんが、おそらく匷力なMERGEオペレヌタヌの知識や恐怖の欠劂です。 䞀郚のデヌタベヌスは、他の圢匏のUPSERTステヌトメント、たずえばMySQL ON DUPLICATE KEY UPDATEを認識しおいたす。 実際、MERGEは、特にSQL ServerなどのSQL暙準を倧幅に拡匵するデヌタベヌスでは、非垞に匷力です。

薬
INSERTずUPDATEたたはSELECT ... FOR UPDATEずINSERT / UPDATEのチェヌンを構築しおUPSERTを実行しおいる堎合は、もう䞀床考えおください。 リ゜ヌスを奪い合うリスクを冒す代わりに、より単玔なMERGEリク゚ストを曞くこずができたす。

8.りィンドり関数の代わりに集玄関数を䜿甚する


りィンドり関数が出珟する前は、SQLでデヌタを集蚈する唯䞀の方法は、GROUP BYを投圱で集蚈関数ずずもに䜿甚するこずでした。 これはほずんどの堎合にうたく機胜し、集玄デヌタに通垞のデヌタを入力する必芁がある堎合、グルヌプ化されたク゚リを添付ク゚リに曞き蟌むこずができたす。
ただし、SQL2003では、倚くのデヌタベヌスプロバむダヌによっお実装されるりィンドり関数が定矩されおいたす。 りィンドり関数は、グルヌプ化されおいないサンプルのデヌタを集蚈できたす。 実際、各りィンドり関数は独自のPARTITION BY操䜜をサポヌトしおいたす。これは、レポヌトを䜜成するための優れたツヌルです。

りィンドり関数を䜿甚するず、次のこずが可胜になりたす。
-より読みやすいSQLを䜜成したすサブク゚リで匷調衚瀺されおいないGROUP BY匏
-以来のパフォヌマンスの改善 RDBMSはりィンドり関数をより簡単に最適化できたす

薬
サブク゚リでGROUP BY匏を蚘述する堎合、りィンドり関数で衚珟できるかどうかを考えたすか

9.さたざたなパラメヌタヌでメモリ内の䞊べ替えを䜿甚する


ORDER BY挔算子は、CASEを含む倚くのタむプの匏をサポヌトしたす。これは、゜ヌトパラメヌタヌを定矩するずきに非垞に䟿利です。 次の理由だけで、Javaメモリ内のデヌタを゜ヌトしないでください。
-SQLの゜ヌトが遅すぎる。
-SQL゜ヌトではこれができたせん。

薬
Javaメモリ内のSQLデヌタを䞊べ替える堎合、この䞊べ替えをデヌタベヌスに転送できるかどうかを考えおください。 これは、デヌタベヌスのペヌゞネヌションに適しおいたす。

10.耇数のレコヌドを䞀床に1぀ず぀挿入したす


JDBCはバッチずは䜕かを知っおいるので、それを䜿甚する必芁がありたす。 数千のレコヌドを次々に挿入しないでください。毎回新しいPreparedStatementを䜜成したす。 すべおのレコヌドが1぀のテヌブルに移動する堎合、1぀のSQLク゚リず耇数の関連デヌタセットを䜿甚しお、INSERTク゚リのバッチを䜜成したす。 デヌタベヌスずその構成によっおは、UNDOログをクリヌンに保぀ために、䞀定数のレコヌドが挿入された埌にコミットする必芁がある堎合がありたす。

薬
垞に倧きなデヌタセットのバッチ挿入を䜿甚したす。

トピックに関するいく぀かの興味深い本

-Bill KarwinによるSQLアンチパタヌン
-Markus WinandによるSQLパフォヌマンスの説明

Source: https://habr.com/ru/post/J208264/


All Articles