最も一般的なSQLアンチパターンは何ですか?[閉まっている]


232

リレーショナルデータベースを扱う私たち全員が、SQLが異なることを学びました(または学び始めました)。望ましい結果を引き出して効率的に行うには、不慣れなパラダイムを習得し、最も身近なプログラミングパターンの一部がここでは機能しないことを発見することを部分的に特徴とする退屈なプロセスを伴います。あなたが見た(またはあなた自身が犯した)一般的なアンチパターンは何ですか?


これは、Stack Overflowに適切な質問の種類について、新しい標準に準拠していない質問です。尋ねられたとき、これは本当ではなかったかもしれません。
David Manheim、

@casperOneは、この質問を受け入れ可能にする祖父となる「歴史的重要性」の条項はありませんか?
エイミーB

26
全体のサイトで最も有用な質問の1つが建設的でないと閉じられているのは悲しいです。
HLGEM、2015年

11
@HLGEM私は完全に同意します。この質問は、StackExchangeで間違っているすべての完璧な例です
Kevin Morse

1
トピックは絶対に重要で関連性があります。しかし、質問はあまりにも自由で、回答がそれぞれエンジニアの個人的なアンチパターンバグベアーを説明しているのはそのためです。
シェーン

回答:


156

ほとんどのプログラマーがデータアクセスレイヤーにUIロジックを混在させる傾向に常に失望しています。

SELECT
    FirstName + ' ' + LastName as "Full Name",
    case UserRole
        when 2 then "Admin"
        when 1 then "Moderator"
        else "User"
    end as "User's Role",
    case SignedIn
        when 0 then "Logged in"
        else "Logged out"
    end as "User signed in?",
    Convert(varchar(100), LastSignOn, 101) as "Last Sign On",
    DateDiff('d', LastSignOn, getDate()) as "Days since last sign on",
    AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' +
        City + ', ' + State + ' ' + Zip as "Address",
    'XXX-XX-' + Substring(
        Convert(varchar(9), SSN), 6, 4) as "Social Security #"
FROM Users

通常、プログラマはデータセットをグリッドに直接バインドするつもりで、SQL Serverフォーマットをクライアント側のフォーマットよりもサーバー側にすると便利なので、これを行います。

上に示したようなクエリは、データレイヤーをUIレイヤーに密結合するため、非常に脆弱です。さらに、このスタイルのプログラミングは、ストアドプロシージャの再利用を完全に防ぎます。


10
可能な最大数の階層/抽象化レイヤーで最大の結合を実現するための優れたポスター子パターン。
dkretz 2008

3
デカップリングには向かないかもしれませんが、パフォーマンス上の理由でそのようなことを頻繁に行ってきましたが、SQL Serverによる反復的な変更は、中間層のコードによる変更よりも高速です。再利用のポイントはわかりません。必要に応じて、SPを実行してcolsの名前を変更することを妨げるものはありません。
ジョー・ピネダ

54
私のお気に入りは、人々がHTMLとJavaScriptを埋め込むときです。例:SELECT '<a href=... onclick="">' + name '</a>'
Matt Rogish

15
このようなクエリを使用すると、単純なalterステートメントでWebサイトのグリッドを編集できます。または、エクスポートの内容を変更するか、レポートの日付を再フォーマットします。これによりクライアントは幸せになり、時間を節約できます。おかげで、感謝の気持ちはありません。このようなクエリを使い続けます。
Andomar 09年

4
@マット・ロギッシュ-イエス、誰かが実際にそうしていますか?
Axarydax 2011年

118

これが私のトップ3です。

番号1。フィールドリストの指定に失敗しました。(編集:混乱を避けるため、これは本番用のコードルールです。作成者でない限り、これは1回限りの分析スクリプトには適用されません。)

SELECT *
Insert Into blah SELECT *

する必要があります

SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist

番号2。カーソル変数とwhileループを使用して、ループ変数でwhileループを実行する場合。

DECLARE @LoopVar int

SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable)
WHILE @LoopVar is not null
BEGIN
  -- Do Stuff with current value of @LoopVar
  ...
  --Ok, done, now get the next value
  SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable
    WHERE @LoopVar < TheKey)
END

番号3。文字列型によるDateLogic。

--Trim the time
Convert(Convert(theDate, varchar(10), 121), datetime)

する必要があります

--Trim the time
DateAdd(dd, DateDiff(dd, 0, theDate), 0)

最近、「1つのクエリの方が2つよりも優れていますか?」というスパイクが見られました。

SELECT *
FROM blah
WHERE (blah.Name = @name OR @name is null)
  AND (blah.Purpose = @Purpose OR @Purpose is null)

このクエリには、パラメーターの値に応じて2つまたは3つの異なる実行プランが必要です。1つの実行プランのみが生成され、このSQLテキストのキャッシュにスタックされます。そのプランは、パラメーターの値に関係なく使用されます。これにより、断続的にパフォーマンスが低下します。2つのクエリ(目的の実行プランごとに1つのクエリ)を記述する方がはるかに優れています。


7
うーん、ポイント2と3だけで+1を差し上げますが、開発者はルール1を上回っています。
アナカタ2008

1
#1の背後にある理由は何ですか?
2008

29
select *を使用すると、テーブルにあるものをすべて取得できます。これらの列は名前と順序を変更する場合があります。クライアントコードは頻繁に名前と順序に依存しています。6か月ごとに、テーブルを変更するときに列の順序を保持する方法を尋ねられます。ルールが守られていたとしても、それは問題ではありません。
Amy B

#2を使用することもあれば、カーソルルートを使用することもあります(最初にクエリの結果をテーブルvarに保存し、その上でカーソルを開きます)。誰かが両方のパフォーマンステストを行ったかどうか、私はいつも疑問に思っていました。
ジョー・ピネダ

4
...もちろん、カーソルは、ほとんどの場合、セットベースのSQLでジョブを実行する方法を理解できなかった場合の最後の手段です。私はかつて、ストアドプロシージャ内の恐ろしい巨大なPL / SQLカーソル(腐ったものの図を描きました)を慎重に解剖するのに約45分費やしました。報告する。実質的なハードウェアでの実行には8.5分かかりました。すべてを図にした後、2秒以内に同じ結果を返す単一のクエリに置き換えることができました。カーソル、男...
クレイグ、

71
  • 人間が読めるパスワードフィールド(egadなど)。自明です。

  • インデックス付きのに対してLIKEを使用しているので、一般的にLIKEとだけ言いたくなります。

  • SQLで生成されたPK値のリサイクル。

  • 誰もまだ神の表について言及しいません。100列のビットフラグ、大きな文字列、整数のような「有機的」なものはありません。

  • 次に、「。ini ファイルがありません」というパターンがあります。CSV、パイプで区切られた文字列、またはその他の解析に必要なデータを大きなテキストフィールドに保存します。

  • また、MS SQLサーバーでは、カーソルをまったく使用しません。特定のカーソルタスクを実行するためのより良い方法があります。

たくさんあるので編集しました!


19
カーソルについて間違っている、私は特定のことをすることが100%正しいか100%間違っていると言うのをためらいます
Shawn

4
これまでのところ、私が見たすべてのカーソル防御の例は、ジョブに間違ったツールを使用しています。しかし、SQLしかわからない場合は、SQLを不適切に使用するか、他の種類のソフトウェアを書くことを学びます。
dkretz 2008

3
@tuinstoel:LIKE '%blah%'はどのようにしてインデックスを使用するのですか?インデックス付けは順序付けに依存しており、この例では文字列のランダムな中間位置を検索します。(インデックスは1番目の文字を1番目に並べるため、真ん中の4文字を見ると実質的にランダムな順序になります...)
MatBailie

12
ほとんどのデータベースサーバー(少なくとも、私が使用したもの)では、LIKEは、プレフィックス検索(LIKE 'xxx%')である限り、つまり、ワイルドカード文字が使用しない限り、インデックスを使用できます。検索文字列の最初に来る。ここで、多目的に少し話をしていると思います。
Cowan

10
それはあなたが好きではないようなものLIKE '%LIKE'です。
ヨハン

62

深く掘り下げる必要はありません。準備されたステートメントを使用しないでください。


3
うん。私の経験では、「エラーをトラップしない」という同じコンテキストで密接に続きました。
dkretz 2008

1
@stesch:これは、ビューを使用したり、レポートの日付を変更したりすることに比べれば、何も変わりません。レポートの日付が変動する場合、ビューはアンチパターンです(ほとんどのアプリケーションではそうです)。これを別の答えに追加しますが、残念ながら閉じられています。
Stefan Steiger

56

無意味なテーブルエイリアスの使用:

from employee t1,
department t2,
job t3,
...

大きなSQLステートメントの読み取りが必要以上に難しくなる


49
エイリアス?地獄私はそのような実際の列名を見ました
アナカタ2008

10
簡潔なエイリアスは問題ありません。意味のある名前が必要な場合は、エイリアスを使用しないでください。
Joel Coehoorn、2008

43
彼は「簡潔」とは言わず、「無意味」と語った。私の本では、e、d、jをクエリ例のエイリアスとして使用することに何の問題もありません。
ロバートロスニー2008

11
絶対に、ロバート-e、d、jは私には問題ありません。
トニーアンドリュース

8
私は従業員にemp、部署にdep、仕事(または多分jb)の仕事を使用します:)
AndreiRînea2008

53
var query = "select COUNT(*) from Users where UserName = '" 
            + tbUser.Text 
            + "' and Password = '" 
            + tbPassword.Text +"'";
  1. ユーザー入力を盲目的に信頼する
  2. パラメータ化クエリを使用しない
  3. クリアテキストのパスワード

これらはすべて、何らかの(任意の)種類のデータベース抽象化レイヤーを使用することで効果的に処理できます。
dkretz 2008

@doofledorfer:そうですね、このような場合には中間層の方が間違いなく優れているでしょうし、結果としてキャッシュを提供することも素晴らしい副作用です。
Joe Pineda

素晴らしい例。開発者がそれを優れたソリューションに置き換える方法を模索している場合、彼らはまともなSQL開発者になるための中間点です。
スティーブマクロード

46

私のバグベアは、マネージングディレクターの親友の犬のグルーマーの8歳の息子によってまとめられた450列のAccessテーブルと、誰かがデータ構造を適切に正規化する方法を知らないためにのみ存在する危険なルックアップテーブルです。

通常、このルックアップテーブルは次のようになります。

ID INT、
名前NVARCHAR(132)、
IntValue1 INT、
IntValue2 INT、
CharValue1 NVARCHAR(255)、
CharValue2 NVARCHAR(255)、
Date1 DATETIME、
日付2日時

このような忌まわしさに依存するシステムを持っているクライアントを見たことがありません。


1
さらに悪いことに、実際に自動的にサポートされるAccessの最新バージョンでは、このValue1、Value2、Value3をさらに奨励することになるのではないかと読んでいます... column fetichism
Joe Pineda

待って-それで8歳の息子は犬のトリマーの息子ですか?
バリーピッカー

28

一番嫌いなのは

  1. テーブル、sprocsなどを作成するときにスペースを使用します。CamelCaseまたはunder_scores、単数形または複数形、大文字または小文字で問題はありませんが、[スペースを入れて]テーブルまたは列を参照する必要があります。私はこれに遭遇しました)本当にイライラします。

  2. 非正規化データ。テーブルを完全に正規化する必要はありませんが、現在の評価スコアや主要なものに関する情報を持つ従業員のテーブルに出くわした場合、いつか別のテーブルを作成する必要があると思われます。次に、それらの同期を保つようにしてください。最初にデータを正規化し、次に非正規化が役立つ場所を見つけたら、それを検討します。

  3. ビューまたはカーソルの過剰使用。ビューには目的がありますが、各テーブルがビューにラップされると多すぎます。カーソルを数回使用しなければなりませんでしたが、通常はこれに他のメカニズムを使用できます。

  4. アクセス。プログラムをアンチパターンにすることはできますか?私たちの職場にはSQL Serverがありますが、技術者以外のユーザーにとっての "使いやすさ"と "使いやすさ"の理由から、多くの人がアクセスを使用しています。ここには多くの情報がありすぎますが、同じような環境にいたことがあればご存知でしょう。


2
#4-<ahref=' stackoverflow.com / questions/327199/… >:) 専用の別のスレッドがあります
dkretz 2008

4
アクセスはDBMSではありません。これはRAD環境で、非常にシンプルなデータベースマネージャが含まれています。SQL Server、Oracleなど VBのような言語とCrystal Reportsのような機能を追加しない限り、それは決して置き換えられません
ジョー・ピネダ

26

SPは、カスタムプロシージャの場所ではなく、最初にシステムプロシージャの場所を検索するため、ストアプロシージャ名のプレフィックスとして使用します。


1
すべてのストアドプロシージャに他の一般的なプレフィックスを使用するように拡張することもできるため、ソートされたリストを選択するのがより困難になります。
dkretz 2008

7
doofledorferコメントの+1 !! 私はこれをたくさん見ました、私はこの馬鹿げたことを見つけて、確かに特定のSPを探すことを非常に難しくします!!! ビューの場合は「vw_」、テーブルの場合は「tbl_」などに拡張されました。
Joe Pineda

1
オブジェクトをファイルにスクリプト化している場合(たとえば、ソース管理、デプロイメント、または移行の場合)、プレフィックスは便利です
Rick

1
すべてのストアドプロシージャの先頭にsp または usp を付けると便利なのはなぜですか。リストをスキャンして必要なものを探すのが難しくなるだけです。
Ryan Lundy

25

一時テーブルとカーソルの過剰使用。


2
「私が知っているのは手続き型言語だけである」という良い証拠。
dkretz 2008

2
何の乱用も当然のことながら望ましくありません。一時テーブル/カーソルを使用する必要がない場合の具体例が役立つでしょう。
ジェイスレア

6
ほとんどの場合、使用頻度の低い一時テーブルが表示されます。SQL Serverでは、多くの場合、1つのモノリシッククエリではなく、一連の一時テーブルを使用してパフォーマンスを向上させます。
Cervo

24

時間値を格納するには、UTCタイムゾーンのみを使用する必要があります。現地時間は使用しないでください。


3
夏時間を考慮しなければならない過去の日付をUTCから現地時間に変換するための適切な簡単な解決策はまだありません。夏時間を考慮する必要があるのは、年や国によって変化する日付、および国内のすべての例外です。したがって、UTCは変換の複雑さからあなたを救いません。ただし、保存されているすべての日時のタイムゾーンを知る方法を持つことが重要です。
ckarras 2009年

1
@CsongorHalmai多くの場所では夏時間を実施しているため、タイムシフトから1時間以内の時間値は不明確になる場合があります。
フランクシュヴィーターマン2017

現在と過去は確かにそうですが、将来、特にかなり遠い未来では、明示的なタイムゾーンが必要になることがよくあります。2049-09-27T17:00:00 New York Timeに書き込まれたばかりで期限切れになる30年のオプションがある場合、21:00:00Zであると無条件に仮定することはできません。米国議会はDST規則を変更する可能性があります。現地時間と実際のタイムゾーン(America / New_York)を分離する必要があります。
John Cowan

23

SCOPE_IDENTITY()の代わりに@@ IDENTITYを使用

この回答から引用:

  • @@ IDENTITYは、すべてのスコープにわたって、現在のセッションの任意のテーブルに対して生成された最後のID値を返します。スコープを超えているため、ここで注意する必要があります。現在のステートメントではなく、トリガーから値を取得できます。
  • SCOPE_IDENTITYは、現在のセッションおよび現在のスコープ内の任意のテーブルに対して生成された最後のID値を返します。一般に、何を使用したいか。
  • IDENT_CURRENTは、任意のセッションおよびスコープの特定のテーブルに対して生成された最後のID値を返します。これにより、上記の2つが必要なものではない場合(非常にまれ)に、値を取得するテーブルを指定できます。これは、レコードを挿入していないテーブルの現在のIDENTITY値を取得する場合に使用できます。

+1は非常に真実であり、除草するのが難しいバグを引き起こす可能性がある
Axarydax 2011年

23

意図されていない何かのために「デッド」フィールドを再利用する(たとえば、「ファクス」フィールドにユーザーデータを格納する)-しかし、迅速な修正として非常に魅力的です!


21
select some_column, ...
from some_table
group by some_column

そして、結果がsome_columnでソートされると仮定します。仮定が当てはまるSybaseでこれを少し見ました(今のところ)。


1
並べ替え順を想定した場合に
限り賛成票を投じ

3
私は、これがバグとして報告されたことを2回以上見たことがあります。
dkretz 2008

6
MySQLでは、ソートするために文書化されています。< dev.mysql.com/doc/refman/5.0/en/select.html >。MySQLを非難します(もう一度)。
derobert 2008

1
Oracleでは、ソートされていない結果は(ほとんど)常にグループ化と一致していました-バージョン10Gまで。ORDER BYを省略していた開発者のためのたくさんの手直し!
Tony Andrews、

1
私はこれがSQL Serverの事実であると述べられたトレーニングクラスにさえいた。私は大声で抗議しなければなりませんでした。20文字を入力して保存するだけの場合は、不明瞭または文書化されていない動作に依存します。
erikkallen 2009

20
SELECT FirstName + ' ' + LastName as "Full Name", case UserRole when 2 then "Admin" when 1 then "Moderator" else "User" end as "User's Role", case SignedIn when 0 then "Logged in" else "Logged out" end as "User signed in?", Convert(varchar(100), LastSignOn, 101) as "Last Sign On", DateDiff('d', LastSignOn, getDate()) as "Days since last sign on", AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' + City + ', ' + State + ' ' + Zip as "Address", 'XXX-XX-' + Substring(Convert(varchar(9), SSN), 6, 4) as "Social Security #" FROM Users

または、すべてを1行に詰め込みます。


以前のコメントのクエリを使用したのは、それが私が入手した最初のSQLステートメントだったからです。
ジャスパーベッカーズ2009

17
  • FROM TableA, TableB WHEREではなくJOINS の構文FROM TableA INNER JOIN TableB ON

  • クエリツールでのテスト中に表示されたのと同じ理由で、ORDER BY句を配置せずにクエリが特定の方法で並べ替えられて返されることを前提としています。


5
私のOracle DBAは、私が「ANSI結合」、つまり正しい方法として提示したものを使用するといつも不平を言っています。しかし、私はそれを続けています、そして彼らは深く彼らがより良いことを知っているのではないかと思います。
スティーブマクロード

1
私は、Oracleが標準SQLの廃止を望んでいると思います。:-)また、MySQL 5で暗黙的および明示的なJOINS(別名ANSI JOIN)を混在させることはできません-動作しません。これは、明示的なJIONのもう1つの議論です。
staticsan 2008

3
A INNER JOIN B ONもアンチパターンだと思います。A INNER JOIN B USINGを使用します。
John Nilsson

Oracleは現在ANSI構文をサポートしていますが、以前は外部結合に対してこの非常に奇妙な構文を使用していましたが、まだそれを使用している人が多すぎます。
Cervo


14

キャリアの最初の6か月でSQLを学び、次の10年間は​​他に何も学びません。特に、ウィンドウ処理/分析SQL機能を学習または効果的に使用していない。特にover()とpartition byの使用。

ウィンドウ関数は、集計関数と同様に、定義された行のセット(グループ)に対して集計を実行しますが、ウィンドウ関数はグループごとに1つの値を返すのではなく、グループごとに複数の値を返すことができます。

ウィンドウ関数の概要については、O'Reilly SQLクックブックの付録Aを参照してください。


12

リストを完成させるために、自分の現在のお気に入りをここに配置する必要があります。私のお気に入りのアンチパターンはクエリのテストではありません

これは次の場合に適用されます。

  1. クエリに複数のテーブルが含まれています。
  2. クエリに最適なデザインがあると思いますが、想定をテストする必要はありません。
  3. 機能する最初のクエリを受け入れますが、最適化に近いかどうかさえわかりません。

また、非定型または不十分なデータに対して実行されたテストはカウントされません。ストアドプロシージャの場合は、テストステートメントをコメントに入れて、結果と共に保存します。それ以外の場合は、結果とともにコード内のコメントに挿入します。


最小限のT-SQLテストに非常に役立つテクニック:SP、UDFなどを定義する.SQLファイルで、IF 1 = 2 BEGIN(コードのサンプルケース、予想される結果を伴うサンプルケースなど)を作成した直後コメントとして)END
Joe Pineda

SQL Serverは、実行されなかったとしても、テストブロック内のコードを解析します。そのため、オブジェクトが変更され、さらに多くのパラメーターまたは異なるタイプなどを受け取る場合、またはオブジェクトが依存するオブジェクトが変更される場合、実行プランを要求するだけでエラーが発生します!
ジョー・ピネダ

実際のデータでテストできるとは限りません。多くの場合、開発サーバー/「テスト」サーバーは十分に支払われておらず、稼働中のサーバーの一部を取得しています。一般に、テストはライブサーバーに対して実行されます。いくつかの場所はより良く、ライブデータを備えたテストまたはステージングサーバーがあります。
Cervo

11

一時的なテーブルの乱用。

具体的には、この種のもの:

SELECT personid, firstname, lastname, age
INTO #tmpPeople
FROM People
WHERE lastname like 's%'

DELETE FROM #tmpPeople
WHERE firstname = 'John'

DELETE FROM #tmpPeople
WHERE firstname = 'Jon'

DELETE FROM #tmpPeople
WHERE age > 35

UPDATE People
SET firstname = 'Fred'
WHERE personid IN (SELECT personid from #tmpPeople)

クエリから一時テーブルを作成しないでください。不要な行を削除するだけです。

そして、はい、私は本番データベースでこの形式のコードのページを見てきました。


1
+1、同意します。ただし、この手法によってパフォーマンスが向上するケースが少なくとも1つまたは2つ見つかりました。関連するクエリは、控えめに言っても複雑でした。
2010

1
確かに

1
条件が非常に複雑な場合は、それを行わなければならないことがあります。確かにそれは極端に悪用される可能性があります。しかし、多くの場合、単純な削除は、最初のクエリでケースを取得するロジックよりもはるかに単純です。また、この句が検索できない場合、最初のクエリが遅くなることがあります。ただし、小さな一時テーブルでそれを実行する方が効率的です。また、ビジネスパーソンが事後に追加し続けるケースを追加し続ける場合もあります。
Cervo

9

逆張りの見方:正規化へのこだわり。

ほとんどのSQL / RBDBシステムは、正規化されていないデータでも非常に役立つ1つの多くの機能(トランザクション、レプリケーション)を提供します。ディスク容量は安価であり、フェッチされたデータを操作/フィルタリング/検索する方が、1NFスキーマを作成してその中のすべての手間(複雑な結合、厄介な副選択)を処理するよりも簡単(コードが簡単で開発時間が短い)の場合があります、など)。

特に、開発の初期段階では、過剰に正規化されたシステムはしばしば時期尚早の最適化であることがわかりました。

(それについてのより多くの考え... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/


22
非正規化はしばしば時期尚早の最適化だと思います。
tuinstoel

ある場合もあるし、ない場合もあります。幸い、多くの場合、テストは簡単で、さまざまなオプションがさまざまなdbニーズで機能します。
グレッグ・リンド

17
正規化は、ディスク容量を節約するためだけのものではありません。また、データの信頼できるソースを作成します。データが1か所だけに保存​​されている場合、一貫性は注意深いコーディングの副産物ではなく、設計の副産物です。
Grant Johnson

複合データをJSON形式で格納することは1つのことです。サポートがますます増えており、意識的なトレードオフです。1つの結合を保存するためにコンマ区切り(またはその他)の値を使用することは、ペニーワイズであり、ポンドバカです。
John Cowan

noSQLソリューションは、マルチテーブルルックアップを排除することにより、データの重複を犠牲にしてパフォーマンス上の利点を示しています。正規化全体を頭に入れます。いくつかの例では、データが複数の場所で収集され、1つのプロセスが可能な限り最速の応答時間を持つようにします。もちろん、信頼できる情報源についての質問が出てきます。
バリーピッカー

9

ここでSQL応答のいくつかに基づいて、これをまとめました。

イベントハンドラーがOOPに対するものであるのと同様に、トリガーはデータベースに対するものであると考えるのは深刻なアンチパターンです。トランザクション(イベント)がテーブルで発生したときにトリガーされるように、古いロジックをトリガーに入れることができるという認識があります。

違います。大きな違いの1つは、トリガーが同期していることです。復讐では、トリガーは行操作ではなくセット操作で同期するためです。OOP側では、まったく反対です。イベントは非同期トランザクションを実装する効率的な方法です。


8

コメントのないストアドプロシージャまたは関数...


そして、ビュー;)テーブル値関数(=パラメータ付きのビュー)を除いて、関数は真です。
Stefan Steiger

7

1)それが「公式の」アンチパターンであることは知りませんが、データベース列の文字列リテラルを魔法の値として使用しないようにします。

MediaWikiのテーブル「イメージ」の例:

img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", 
    "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
img_major_mime ENUM("unknown", "application", "audio", "image", "text", 
    "video", "message", "model", "multipart") NOT NULL default "unknown",

(私はちょうど異なるケーシングに気づきます、避けるべきもう一つのこと)

私は、int主キーを使用してImageMediaTypeテーブルとImageMajorMimeテーブルへのintルックアップなどのケースを設計します。

2)特定のNLS設定に依存する日付/文字列変換

CONVERT(NVARCHAR, GETDATE())

フォーマット識別子なし


また、構文のインデントもありません。ああ。
dkretz 2008

2
なぜこれが悪いのですか?確かに値のセットを表現しようとしている場合、これはルックアップテーブルと同じように機能し、それを呼び出すコードに適しています。私のアプリコードには、ルックアップテーブルの特定の行にマップするアプリコードの列挙型ではなく、DBの列挙型制約にマップする列挙型が必要です。すっきりした感じです。
ジャックライアン

@JackRyan:後で列挙リストを変更するときは、2つの場所で変更することを忘れないでください。DRYに違反しています。データベースは真実の単一の情報源である必要があります。
ジェラット

7

クエリ内の同一のサブクエリ。


10
残念ながら、それを回避できない場合もあります。SQL2000では「WITH」キーワードがなく、UDFを使用して一般的なサブクエリをカプセル化すると、パフォーマンスが低下する場合があり、MSの責任を負っています...
Joe Pineda

まあ、うまくいけば、彼らは最近のいずれかにそれを追加することに取りかかるでしょう。
EvilTeach 2008

SQL 2000では、テーブル変数を使用できます。
再帰的

@recursive:テーブル変数にインデックスを付けることはできません。これにより、サブクエリよりも遅くなることがよくあります。ただし、カスタムインデックスを持つ一時テーブルを使用できます。
Rick

かっこいい、何年もSQLを使用していて、共通テーブル式が存在することさえ知りませんでした(私はそれらを必要としていましたが)。今私がやります!ありがとう!
sleske 2009年

7
  • 変更されたビュー-通知や理由なしに頻繁に変更されるビュー。変更は、最も不適切なときに通知されるか、またはさらに悪いことに、通知されない場合があります。誰かがその列のより良い名前を考えたため、アプリケーションが壊れる可能性があります。原則として、ビューは、コンシューマとの契約を維持しながら、ベーステーブルの有用性を拡張する必要があります。問題を修正しますが、機能を追加したり、動作を変更したりしないでください。これにより、新しいビューが作成されます。軽減するには、他のプロジェクトとビューを共有せず、プラットフォームで許可されている場合はCTEを使用します。ショップにDBAがいる場合、おそらくビューを変更することはできませんが、その場合、すべてのビューが古くなったり、役に立たなくなったりします。

  • !Paramed-クエリには複数の目的がありますか?たぶんそれを読んだ次の人は深い瞑想をするまでわからないでしょう。現時点でそれらが必要ない場合でも、デバッグすることが「ただ」であっても可能性があります。パラメータを追加すると、メンテナンス時間が短縮され、物が乾燥した状態に保たれます。where句がある場合は、パラメータが必要です。

  • ケースなしの場合-

    SELECT  
    CASE @problem  
      WHEN 'Need to replace column A with this medium to large collection of strings hanging out in my code.'  
        THEN 'Create a table for lookup and add to your from clause.'  
      WHEN 'Scrubbing values in the result set based on some business rules.'  
        THEN 'Fix the data in the database'  
      WHEN 'Formating dates or numbers.'   
        THEN 'Apply formating in the presentation layer.'  
      WHEN 'Createing a cross tab'  
        THEN 'Good, but in reporting you should probably be using cross tab, matrix or pivot templates'   
    ELSE 'You probably found another case for no CASE but now I have to edit my code instead of enriching the data...' END  

その3番目のものを愛した。私はすでにローカルで使用しています...
alphadogg 2009

小道具をありがとう。:)
jason saldo

5

私が最も多く見つけ、パフォーマンスの点でかなりのコストがかかる可能性がある2つは次のとおりです。

  • セットベースの式の代わりにカーソルを使用する。これは、プログラマーが手順に従って考えているときに頻繁に発生すると思います。

  • 派生したテーブルへの結合でジョブを実行できる場合の、相関サブクエリの使用。


あなたが私があなたが何を意味していると思うかを意味するなら私は同意します。ただし、相関サブクエリは派生テーブルIIRCの一種です。
dkretz 2008

1
派生テーブルはセット操作ですが、相関サブクエリは外部クエリの各行に対して実行されるため、効率が低下します(10回のうち9回)
Mitch Wheat

数年前に、SQL Sが何らかの形で相関クエリの処理に最適化されていることに驚きました。単純なクエリでは、JOINを使用した論理的に同等のクエリと同じ実行プランが得られます。また、Oracleを完全に機能させる相関クエリは、SQL Sでの実行速度が遅いだけです。
ジョー・ピネダ

だから私はいつも両方の方法でテストしています。そして、私は通常それを両方の方法で試します。実際、SQL Serverの場合はとにかく、通常、相関sqが遅くなることはありません。
dkretz 2008

3
相関サブクエリと結合は(ほとんどの場合)IDENTICALであることを理解してください。それらは互いに最適化された異なるものではなく、同じ操作の異なるテキスト表現です。
erikkallen 2009

5

一時テーブルにデータを入れると、特にSQL ServerからOracleに切り替える人は、一時テーブルを使いすぎる傾向があります。ネストされた選択ステートメントを使用するだけです。


5

SQLアプリケーション(個々のクエリとマルチユーザーシステムの両方)が高速または低速になる理由についてよく理解していないクエリを作成する開発者。これには、以下に関する無知が含まれます。

  • ほとんどのクエリのボトルネックがCPUではなくI / Oであることを考えると、物理I / O最小化戦略
  • さまざまな種類の物理ストレージアクセスのパフォーマンスへの影響(たとえば、多くのシーケンシャルI / Oは、多くの小さなランダムI / Oよりも高速ですが、物理ストレージがSSDの場合は、より少なくなります!)
  • DBMSが不適切なクエリプランを生成した場合にクエリを手動で調整する方法
  • データベースのパフォーマンスの低下を診断する方法、遅いクエリを「デバッグ」する方法、クエリプラン(または選択したDBMSに応じてEXPLAIN)を読み取る方法
  • スループットを最適化し、マルチユーザーアプリケーションでのデッドロックを回避するためのロック戦略
  • データセットの処理を処理するためのバッチ処理およびその他のトリックの重要性
  • スペースとパフォーマンスのバランスを最適化するためのテーブルとインデックスの設計(たとえば、インデックスをカバーする、可能な場合はインデックスを小さく保つ、必要な最小サイズにデータ型を減らすなど)

3

栄光のISAM(Indexed Sequential Access Method)パッケージとしてのSQLの使用。特に、SQLステートメントを1つの大きなステートメントに結合するのではなく、カーソルをネストします。実際にはオプティマイザができることはあまりないので、これは「オプティマイザの乱用」としてカウントされます。これは、最大の非効率性のために準備されていないステートメントと組み合わせることができます:

DECLARE c1 CURSOR FOR SELECT Col1, Col2, Col3 FROM Table1

FOREACH c1 INTO a.col1, a.col2, a.col3
    DECLARE c2 CURSOR FOR
        SELECT Item1, Item2, Item3
            FROM Table2
            WHERE Table2.Item1 = a.col2
    FOREACH c2 INTO b.item1, b.item2, b.item3
        ...process data from records a and b...
    END FOREACH
END FOREACH

(ほとんどの場合)正しい解決策は、2つのSELECTステートメントを1つに結合することです。

DECLARE c1 CURSOR FOR
    SELECT Col1, Col2, Col3, Item1, Item2, Item3
        FROM Table1, Table2
        WHERE Table2.Item1 = Table1.Col2
        -- ORDER BY Table1.Col1, Table2.Item1

FOREACH c1 INTO a.col1, a.col2, a.col3, b.item1, b.item2, b.item3
    ...process data from records a and b...
END FOREACH

二重ループバージョンの唯一の利点は、内部ループが終了するため、表1の値の間の区切りを簡単に見つけることができることです。これは、コントロールブレークレポートの要素になる可能性があります。

また、アプリケーションでの並べ替えは通常、ノーノーです。


スタイルは、この構文ではありませんが、私の経験では特にPHPで蔓延しています。
dkretz 2008

構文は実際にはIBM Informix-4GLですが、説明の仕方をそれほど必要としないことは明らかです(私はそう思います)。また、プログラミング言語に関係なく、多くのSQLプログラムでスタイルが横行しています。
Jonathan Leffler

よく知られているアンチパターン(暗黙の結合)を使用してアンチパターンを説明しているという事実を除けば、一種のポイントを打ち負かしています。
ヨハン

そしてもちろん、カーソルの使用はすべてSQlアンチパターンです。事実上すべてのカーソルは、セットベースの操作として書き直すことができます。できないのは、長年の経験があり、データベースベースの内部がどのように機能するかを理解しているDBAだけが書くべきものです。アプリケーション開発者がSQLカーソルを書き込む必要はありません。
HLGEM、2015年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.