SQL ステートメントのパフォーマンスの最適化

SQL ステートメントのパフォーマンスの最適化

この記事では、52 の SQL ステートメントのパフォーマンス最適化戦略について説明します。

1. クエリを最適化するには、テーブル全体のスキャンを回避する必要があります。まず、WHERE および ORDER BY に関係する列にインデックスを構築することを検討してください。


2. WHERE 句内のフィールドの NULL 値を判断しないようにしてください。NULL はテーブル作成時のデフォルト値ですが、ほとんどの場合、NOT NULL を使用するか、0、-1 などの特別な値を使用する必要があります。デフォルト値として。


3. WHERE 句では != または <> 演算子を使用しないようにしてください。MySQL は、演算子 <、<=、=、>、>=、BETWEEN、IN、および場合によっては LIKE のインデックスのみを使用します。


4. 条件を接続するために WHERE 句で OR を使用することは避けてください。そうしないと、エンジンはインデックスの使用を放棄し、テーブル全体のスキャンを実行します。UNION を使用してクエリを結合できます。

	select id from t where num = 10 
	union all select id from t where num = 20

5. IN と NOT IN も注意して使用する必要があります。使用しないと、テーブル全体のスキャンが発生します。連続値の場合、BETWEEN を使用できる場合は IN を使用しないでください。

	select id from t where num between 1 and 3

6. 次のクエリでもテーブル全体のスキャンが行われますが、効率を向上させたい場合は、全文検索を検討してください。

	select id from t where name like '%abc%'
	select id from t where name like '%abc'

この場合、インデックスが使用されます

	select id from t where name like 'abc%'

7. WHERE 句でパラメータが使用されている場合、テーブル全体のスキャンも発生します。


8. WHERE 句内のフィールドに対して式演算や関数演算を実行しないようにしてください。


9. 多くの場合、IN の代わりに EXISTS を使用するのが良い選択です。

	select num from a where num in(select num from b)

次のステートメントに置き換えます

	select num from a where exists(select 1 from b where num = a.num)

10. インデックスにより、対応する SELECT の効率が向上しますが、INSERT および UPDATE の効率も低下します。インデックスは INSERT および UPDATE 中に再構築される可能性があるため、特定の状況に応じてインデックスの構築方法を慎重に検討する必要があります。1 つのテーブルに 6 つを超えるインデックスを持たないことが最善ですが、多すぎる場合は、使用頻度の低い列に構築されたインデックスが必要かどうかを検討する必要があります。


11. クラスター化インデックス データ列の順序はテーブル レコードの物理的な格納順序であるため、クラスター化インデックス データ列の更新はできるだけ避けてください。この列の値が変更されると、テーブル レコード全体の順序が調整されます。かなりのリソースを消費します。アプリケーション システムがクラスター化インデックスのデータ列を頻繁に更新する必要がある場合は、インデックスをクラスター化インデックスとして構築する必要があるかどうかを検討する必要があります。


12. 数値フィールドを使用するようにします。数値情報のみを含むフィールドを文字型として設計しないと、クエリと接続のパフォーマンスが低下し、ストレージのオーバーヘッドが増加します。


13. 可能な限り、char と nchar の代わりに varchar と nvarchar を使用します。その理由は、第一に、可変長フィールドの記憶スペースが小さいため、記憶スペースを節約できること、第二に、クエリの場合、比較的小さなフィールドでの検索効率が明らかに高いためです。


14. return all は使用しないほうがよい

	select * from t

「 * 」を特定のフィールドのリストに置き換え、使用されていないフィールドは返さないでください。


15. クライアントに大量のデータを返さないようにしてください。データの量が大きすぎる場合は、対応する需要が妥当であるかどうかを検討する必要があります。


16. テーブルのエイリアスを使用する (Alias): SQL ステートメントで複数のテーブルを接続する場合は、テーブルのエイリアスを使用し、各列の先頭にエイリアスを付けてください。これにより、解析時間が短縮され、列の曖昧さによって引き起こされる構文エラーが減少します。


17. 「一時テーブル」を使用して中間結果を一時的に保存します。
SQL ステートメントを簡素化する重要な方法は、一時テーブルを使用して中間結果を一時的に保存することです。しかし、一時テーブルの利点はそれ以上です。一時的な結果は一時テーブルに一時的に保存され、後続のクエリは tempdb に保存されます。これにより、プログラム内のメイン テーブルの複数回のスキャンが回避され、「共有ロック」が大幅に削減されます。 「プログラム実行中のブロック。「更新ロック」によりブロックが軽減され、同時実行パフォーマンスが向上します。


18. 同時パフォーマンスを向上させるために、読み取りと書き込みが相互にブロックされるため、一部の SQL クエリ ステートメントに Nolock を追加する必要があります。一部のクエリでは、読み取り時に書き込みを許可するために nolock を追加できますが、欠点は、コミットされていないダーティ データが読み取られる可能性があることです。


19. 一般的な簡略化ルールは次のとおりです。
テーブル接続 (JOIN) は 5 つを超えてはならず、中間結果を格納するために一時テーブルまたはテーブル変数の使用を検討してください。使用するサブクエリを減らし、ビューをあまり深くネストしないでください。一般に、ビューを 2 つ以上ネストしないことをお勧めします。


20. クエリが必要な結果を事前に計算してテーブルに入力し、クエリ時に SELECT を実行します。これは、病院の入院費の計算など、SQL7.0 以前では最も重要な方法でした。


21. OR 句は複数のクエリに分解でき、複数のクエリを UNION で接続できます。速度はインデックスを使用するかどうかにのみ関係し、クエリでジョイント インデックスを使用する必要がある場合は、UNION ALL を使用して実行する方が効率的です。複数の OR 句はインデックスを使用せず、UNION 形式で書き換えてインデックスの一致を試みます。重要な問題は、インデックスを使用するかどうかです。


22. INの後ろの値のリストは、最頻値を先頭、最少値を最後に配置して判定回数を減らします。


23. ストアド プロシージャを使用するなど、ネットワーク オーバーヘッドを削減するためにサーバー上でデータ処理を行うようにしてください。
ストアドプロシージャとは、SQL文をコンパイル、最適化して実行計画にまとめ、データベースに格納する制御フロー言語の集合体で、当然速度も速いです。繰り返し実行される動的 SQL は、Tempdb に配置される一時ストアド プロシージャを使用できます。


24. サーバーに十分なメモリがある場合は、効率を最大化できるスレッド数 = 最大接続数 + 5を構成します。それ以外の場合は、構成されたスレッド数 < 最大接続数を使用し、スレッド プールを有効にします。 SQL SERVER で問題を解決するには、接続数 + 5 が最大値のままの場合、サーバーのパフォーマンスに重大な損害が生じます。


25. クエリの関連付けは書き込み順序と同じです

	select a.personMemberID, * from a, b 
	where personMemberID = b.referenceid and a.personMemberID = 'JCNPRH39681' (A = B, B = '号码'select a.personMemberID, * from a, b 
	where a.personMemberID = b.referenceid and a.personMemberID = 'JCNPRH39681' 
	and b.referenceid = 'JCNPRH39681' (A = B, B = '号码', A = '号码'select a.personMemberID, * from a, b 
	where b.referenceid = 'JCNPRH39681' and a.personMemberID = 'JCNPRH39681' (B = '号码', A = '号码'

26. レコードがあるかどうかを判断するには、select count(1) の代わりに EXISTS を使用してみてください。count 関数は、テーブル内のすべての行をカウントする場合にのみ使用され、count(1) は count(*) より効率的です。
27. 「">」の代わりに「">=」を使用してみてください。

28. インデックスの使用に関する仕様:

  • インデックスの作成はアプリケーションと組み合わせて検討する必要があり、大規模な OLTP テーブルのインデックスは 6 つを超えないようにすることをお勧めします。
  • 可能な限りインデックス フィールドをクエリ条件として使用します (特にクラスター化インデックス)。必要に応じて、インデックス Index_name を使用して、指定したインデックスを強制することができます。
  • 大きなテーブルをクエリする場合はテーブル スキャンの実行を避け、必要に応じて新しいインデックスを作成することを検討してください。
  • インデックス フィールドを条件として使用する場合、インデックスが結合インデックスの場合、インデックスの最初のフィールドを条件として使用して、システムが確実にインデックスを使用するようにする必要があります。そうでない場合、インデックスは使用されません。
  • インデックスのメンテナンスに注意し、定期的にインデックスを再構築し、ストアド プロシージャを再コンパイルします。

29. 次の SQL 条件文の列には適切にインデックスが付けられていますが、実行速度が非常に遅いです。
	SELECT * FROM record WHERE substrIng(card_no, 1, 4) = '5378'  --13秒
	SELECT * FROM record WHERE amount/30 < 1000 --11秒 
	SELECT * FROM record WHERE convert(char(10), date, 112) = '19991201' --10秒

分析します:

WHERE 句内の列に対する操作の結果は、SQL 実行時に列ごとに計算されるため、その列に対してインデックスを使用せずにテーブル検索を行う必要があります。

これらの結果がクエリのコンパイル時に利用可能な場合は、SQL オプティマイザーによってインデックスを使用し、テーブル検索を回避して最適化できるため、SQL を次のように書き換えます。

	SELECT * FROM record WHERE card_no like '5378%' -- < 1秒
	SELECT * FROM record WHERE amount < 1000*30 -- < 1秒 
	SELECT * FROM record WHERE date = '1999/12/01' -- < 1秒

30. 処理する挿入または更新のバッチがある場合は、バッチ挿入またはバッチ更新を使用し、レコードを 1 つずつ更新しないでください。


31. すべてのストアド プロシージャで SQL ステートメントが使用できる場合、それらを実装するためにループを使用することはありません。

たとえば、前月の毎日をリストするには、connect by を使用して再帰的にクエリを実行します。前月の初日から末日までのループは決して使用しません。


32. テーブル名の最も効率的な順序を選択します (ルールベースのオプティマイザーでのみ有効):
Oeacle のパーサーは FROM 句内のテーブル名を右から左の順序で処理し、FROM 句は最後のテーブル ( FROM 句に複数のテーブルがある場合は、レコード数が最も少ないテーブルをベース テーブルとして選択する必要があります。

クエリに 3 つ以上のテーブルが接続されている場合は、交差テーブルをベース テーブルとして選択する必要があります。交差テーブルは、他のテーブルによって参照されるテーブルを参照します。


33. GROUP BY ステートメントの効率を向上させるために、GROUP BY の前に不要なレコードをフィルターで除外できます。次の 2 つのクエリは同じ結果を返しますが、2 番目のクエリの方が大幅に高速です。

非効率的な:

	SELECT JOB, AVG(SAL) FROM EMP GROUP BY JOB HAVING JOB = 'PRESIDENT' OR JOB = 'MANAGER'

効率的:

	SELECT JOB, AVG(SAL) FROM EMP WHERE JOB = 'PRESIDENT' OR JOB = 'MANAGER' GROUP BY JOB

34. Oracle は常に最初に SQL ステートメントを解析し、小文字を大文字に変換してから実行するため、SQL ステートメントには大文字を使用します。


35. エイリアスの使用。エイリアスは大規模データベースのアプリケーション スキルです。つまり、テーブル名と列名がクエリ内で文字でエイリアス化され、クエリ速度は接続テーブルを構築するより 1.5 倍速くなります。


36. デッドロックを回避し、ストアド プロシージャとトリガー内の同じテーブルに常に同じ順序でアクセスします。トランザクションはできるだけ短くし、トランザクションに含まれるデータ量をできるだけ減らす必要があります。ユーザーを決して待機しないでください。トランザクション内の入力。


37. 一時テーブルの使用を避ける必要がない限り、一時テーブルの使用を避け、代わりにテーブル変数を使用してください。ほとんどの場合 (99%)、テーブル変数はメモリ内に常駐するため、TempDb データベース内に常駐する一時テーブルよりも高速です。そのため、一時テーブルでの操作にはデータベース間通信が必要であり、必然的に遅くなります。


38. トリガーを使用しないのが最善です。

  • トリガーのトリガーとトリガー イベントの実行自体は、リソースを消費するプロセスです。
  • 制約を使用して実装できる場合は、トリガーを使用しないようにしてください。
  • 異なるトリガー イベント (挿入、更新、削除) に同じトリガーを使用しないでください。
  • トリガーでトランザクション コードを使用しないでください

39. インデックス作成ルール:

  • テーブルの主キーと外部キーにはインデックスが必要です。
  • 300 を超えるデータを含むテーブルにはインデックスが必要です。
  • 他のテーブルと頻繁に結合されるテーブルの場合、結合フィールドにインデックスを確立する必要があります。
  • WHERE 句に頻繁に現れるフィールド、特に大きなテーブルのフィールドにはインデックスを付ける必要があります。
  • インデックスは、選択性の高いフィールドに基づいて構築する必要があります。
  • インデックスは小さなフィールドに対して構築する必要があり、大きなテキスト フィールドや超長いフィールドに対してもインデックスを構築しないでください。
  • 複合インデックスの確立は慎重に分析する必要があり、代わりに単一フィールド インデックスを使用するようにしてください。
  • 複合インデックスのメイン列フィールドを正しく選択します。これは通常、より選択性の高いフィールドです。
  • 複合インデックスの複数のフィールドが WHERE 句に AND 形式で同時に現れることがよくありますか? 単一フィールドのクエリはほとんどありませんか? 「はい」の場合は複合インデックスを構築できますが、それ以外の場合は単一フィールド インデックスを検討してください。
  • 複合インデックスに含まれるフィールドが WHERE 句に単独で出現することが多い場合、複合インデックスは複数の単一フィールド インデックスに分解されます。
  • 複合インデックスに 3 つを超えるフィールドが含まれている場合は、その必要性を慎重に検討し、複合フィールドを減らすことを検討してください。
  • これらのフィールドに単一フィールド インデックスと複合インデックスの両方がある場合、通常は複合インデックスを削除できます。
  • データ操作が頻繁に行われるテーブルの場合は、インデックスを作成しすぎないでください。
  • 実行計画への悪影響を避けるために、不要なインデックスを削除します。
  • テーブルにインデックスが作成されると、ストレージのオーバーヘッドが増加し、挿入、削除、更新の各操作の処理オーバーヘッドも増加します。さらに、複合インデックスが多すぎると、単一フィールド インデックスの場合は一般的に役に立ちませんが、逆に、データの追加と削除のパフォーマンスも低下し、特に頻繁に更新されるテーブルの場合、悪影響はさらに大きくなります。
  • 多数の重複値を含むデータベース内のフィールドにインデックスを作成しないようにしてください。

40. MySQL クエリ最適化の概要:

低速クエリ ログを使用して低速クエリを見つけ、実行プランを使用してクエリが適切に実行されているかどうかを判断し、常にクエリをテストして最適に実行されているかどうかを確認します。

パフォーマンスは時間の経過とともに常に変化します。テーブル全体でカウント (*) を使用することは避けてください。テーブル全体がロックされる可能性があります。クエリの一貫性を維持して、後続の同様のクエリでクエリ キャッシュを使用できるようにします。必要に応じて、DISTINCT の代わりに GROUP BY を使用します。 WHERE、GROUP BY、ORDER BY 句でインデックス付き列を使用すると、インデックスが単純になり、複数のインデックスに同じ列が含まれないようになります。

MySQL は間違ったインデックスを使用する場合があります。この場合は USE INDEX を使用し、SQL_MODE = STRICT の使用の問題を確認してください。レコード数が 5 未満のインデックス フィールドには、UNION の OR の代わりに LIMIT を使用してください。

更新前の SELECT を回避するには、INSERT ON DUPLICATE KEY または INSERT IGNORE を使用します。実装には UPDATE を使用せず、MAX も使用しません。インデックス フィールドと ORDER BY 句を使用します。LIMIT M、N は実際にクエリを遅くする可能性があります。使用は控えめにし、サブクエリではなく WHERE 句で UNION を使用します。MySQL を再起動した後は、データベースをウォームアップしてメモリ内のデータを確保し、クエリを高速に実行します。オーバーヘッドを削減するために、複数の接続ではなく永続的な接続を検討します。

サーバーの負荷の使用を含むクエリのベンチマーク。単純なクエリが他のクエリに影響を与える場合があります。サーバーの負荷が増加した場合、SHOW PROCESSLISE を使用して低速で問題のあるクエリを確認し、開発環境で生成されたミラー データですべてをテストします。クエリ。


41. MySQL バックアップ プロセス:

  • セカンダリ レプリカ サーバーからのバックアップ。
  • データの依存関係や外部キー制約の不一致を避けるために、バックアップの進行中はレプリケーションを停止します。
  • MySQL を完全に停止し、データベース ファイルからバックアップを作成します。
  • バックアップに MySQL ダンプを使用する場合は、レプリケーションが中断されないように、バイナリ ログ ファイルもバックアップしてください。
  • LVM スナップショットは信頼しないでください。データの不整合が生じ、将来問題が発生する可能性があります。
  • 単一テーブルのリカバリを容易にするために、データが他のテーブルから分離されている場合は、テーブルごとにデータをエクスポートします。
  • MySQL ダンプを使用する場合は、-opt を使用してください。
  • バックアップ前にテーブルをチェックして最適化します。
  • インポートを高速化するために、インポート中に外部キー制約が一時的に無効になります。
  • インポートを高速化するには、インポート中に一意性の検出を一時的に無効にします。
  • データ サイズの増加を監視できるように、各バックアップ後にデータベース、テーブル、インデックスのサイズを計算します。
  • 自動スケジュール スクリプトを使用して、レプリケーション インスタンスのエラーと遅延を監視します。
  • 定期的にバックアップを実行してください。

42. クエリ バッファはスペースを自動的に処理しません。そのため、SQL ステートメントを作成するときは、スペース、特に SQL の先頭と末尾のスペースの使用を最小限に抑える必要があります (クエリ バッファは最初と最後のスペースを自動的にインターセプトしないため)。スペース)。


43. サブテーブル分割の基準としてmidを使用するのはメンバーにとって便利ですか?

一般的なビジネス要件では、基本的にユーザー名をクエリのベースとして使用しますが、通常はユーザー名をハッシュモジュロとして使用してテーブルを分割する必要があります。
サブテーブルに関しては、MySQL のパーティション関数がこれを実行し、コードに対して透過的であるため、コード レベルで実装するのは不合理と思われます。


44. データベース内の各テーブルの主キーとして ID を設定する必要があります。最適なのは INT 型 (UNSIGEND の使用を推奨) で、自動的に増加する AUTO_INCREMENT フラグを設定します。


45. すべてのストアド プロシージャとトリガーの最初に SET NOCOUNT ON を設定し、最後に SET NOCOUNT OFF を設定します。ストアド プロシージャとトリガーのすべてのステートメントが実行された後に、クライアントに DONE_IN_PROC メッセージを送信する必要はありません。


46. MySQL クエリは高速クエリ キャッシュを有効にすることができます。これは、データベースのパフォーマンスを向上させるための効果的な MySQL チューニング方法の 1 つです。同じクエリが複数回実行される場合、キャッシュからデータをフェッチし、データベースから直接返す方がはるかに高速です。


47. EXPLAIN SELECT クエリは、表示効果を追跡するために使用されます。

EXPLAIN キーワードを使用すると、MySQL が SQL ステートメントをどのように処理するかを知ることができます。これは、クエリ ステートメントまたはテーブル構造におけるパフォーマンスのボトルネックを分析するのに役立ちます。EXPLAIN のクエリ結果では、インデックスの主キーがどのように使用され、データ テーブルがどのように検索および並べ替えられるかについてもわかります。


48. データが 1 行しかない場合は、LIMIT 1 を使用します。

テーブルにクエリを実行すると、結果が 1 つだけになることがすでにわかっていますが、場合によってはカーソルをフェッチしたり、返されたレコードの数を確認したりする必要があるためです。

この場合、LIMIT 1 を追加するとパフォーマンスが向上する可能性があります。このようにして、MySQL データベース エンジンは、レコードに一致する次のデータのクエリを続行するのではなく、データを見つけた後に検索を停止します。


49. テーブルに適切なストレージ エンジンを選択します

  • myisam : アプリケーションは主に読み取りと挿入の操作で、更新と削除は少量のみで、トランザクションの整合性と同時実行性の要件はそれほど高くありません。
  • InnoDB : トランザクション処理、および同時実行条件下で必要なデータの一貫性。挿入とクエリに加えて、多くの更新と削除が含まれます。(InnoDB は、削除と更新によって発生するロックを効果的に削減します)
    トランザクションをサポートする InnoDB テーブルの場合、速度に影響を与える主な理由は、AUTOCOMMIT のデフォルト設定がオンになっており、プログラムがトランザクションを開始するために BEGIN を明示的に呼び出していないことです。すべての挿入でそれらは自動的に送信され、速度に重大な影響を与えます。SQL を実行する前に begin を呼び出すことができ、複数の SQL でトランザクションを形成することができます (自動コミットが有効になっている場合でも)。これにより、パフォーマンスが大幅に向上します。

50. テーブルのデータ型を最適化し、適切なデータ型を選択します。

原則: 通常は小さい方が良い、シンプルであることが良い、すべてのフィールドはデフォルト値を持つ必要があり、NULL を避けるようにしてください。

例: データベース テーブルを設計するときは、占有するディスク領域を小さくするために、できるだけ小さい整数型を使用します。(intよりmediumintの方が適しています)

時間フィールドなど: 日付時刻とタイムスタンプ。datetime は 8 バイトを占め、timestamp は 4 バイトを占めますが、半分しか使用されていません。また、タイムスタンプで表される範囲は1970~2037となっており、更新時刻に適しています。

MySQL は大量のデータへのアクセスを十分にサポートできますが、一般的に言えば、データベース内のテーブルが小さいほど、クエリの実行は速くなります。したがって、テーブルを作成するときに、パフォーマンスを向上させるために、テーブル内のフィールドの幅をできるだけ小さく設定できます。

たとえば、郵便番号フィールドを定義するときに、それが char (255) に設定されている場合、明らかにデータベースに不必要なスペースが追加されます。char(6) が問題なく機能するため、varchar 型を使用することも冗長です。

「都道府県」や「性別」などの一部のテキストフィールドについては、ENUM タイプとして定義できます。MySQL では ENUM 型は数値データとして扱われるため、数値データはテキスト型よりもはるかに高速に処理されます。


51. 文字列データ型: char、varchar、text の違いを選択します。


52. 列に対する操作はすべて、データベース関数、計算式などを含むテーブル スキャンにつながります。クエリを実行するときは、操作をできるだけ等号の右側に移動します。


良いことの法則:すべては最終的には良いことになる、それが良いことではない場合、それはまだ終わりではないことを意味します。

おすすめ

転載: blog.csdn.net/Cike___/article/details/113928791
おすすめ