SQL チューニングを行う理由
まず第一に、なぜ SQL チューニングが必要なのかを理解する必要があります。実際、企業が SQL チューニングを必要とする最も重要なことは、企業がコストを節約できるようにすることです。なぜそう言えるのでしょうか? この比較を見てみましょう
- コストの最適化: ハードウェア > システム構成 > データベース テーブル構造 > SQL とインデックス
- 最適化効果: ハードウェア<システム構成<データベーステーブル構造<SQLおよびインデックス
したがって、SQL が適切に調整されていれば、システム全体の可用性が大幅に向上することがわかります。
五つの原則
通常、SQL 最適化では次の 5 つの原則を実行します。
1. データ アクセスの削減: 適切なフィールド タイプを設定し、圧縮を有効にし、インデックス アクセスなどを通じてディスク IO を削減し、重要でないデータをサブデータベース ストレージとして Redis または MongoDB に保存します。
2. 返すデータを少なくします: ディスク IO とネットワーク IO を削減するために、必要なフィールドまたはページング データのみを返します。
3. 接続数の削減: DML のバッチ操作 (一般的に言えば、追加、削除、変更、確認) と関数ストレージの実行が簡単です。
4. サーバーの CPU オーバーヘッドを削減します。データベースの並べ替え操作とテーブル全体のクエリを最小限に抑え、CPU メモリの使用量を削減します。
5. より多くのリソースを利用する: テーブル パーティションを使用すると、並列処理が増加し、CPU リソースの使用率が最大化されます。
SQL 最適化の原理を理解するには、まず SQL の実行順序を理解する必要があります。
このリンクにジャンプできます。SELECT ステートメント - 文法順序_Shizhu Baishao のブログ - CSDN ブログ
SQL 最適化戦略について
1. インデックスを取得しない状況を回避する
以下は、データベース エンジンがインデックスを放棄し、テーブル全体のスキャンを実行する原因となる状況と、その最適化戦略を示しています。
1. フィールドの先頭であいまいなクエリを避けるようにしてください。
SELECT *
FROM user
WHERE username LIKE '%白%'
--->尽量在字段后面使用模糊查询。
SELECT *
FROM user
WHERE username LIKE '白%'
2. in の使用と not in の使用を避けるようにしてください。
SELECT *
FROM user
WHERE id IN (2,3)
--->如果是连续数值,可以用between代替
SELECT *
FROM user
WHERE id BETWEEN 2 AND 3
サブクエリの場合は、代わりにexistsを使用できます。
-- 不走索引
select * from A where A.id in (select id from B);
-- 走索引
select * from A where exists (select * from B where B.id = A.id);
3. または
SELECT *
FROM t
WHERE id = 1 OR id = 3
--->可以使用union代替or
SELECT * FROM t WHERE id = 1
UNION
SELECT * FROM t WHERE id = 3
4. NULL と判断しないようにする
SELECT *
FROM t
WHERE score IS NULL
--->可以给默认字段添加默认值0,对0进行判断
SELECT *
FROM t
WHERE score = 0
5. where 条件の等号の左側で式や関数の演算を実行しないようにしてください。
--->全表扫描
SELECT * FROM T WHERE score/10 = 9
--->走索引
SELECT * FROM T WHERE score = 10*9
6. データ量が多い場合は、1=1 の条件は避けてください。通常、クエリ条件の組み立てを容易にするために、この条件をデフォルトで使用します。
SELECT
username, age, sex
FROM T
WHERE 1=1
最適化方法:SQLをコードで組み立てる際に判断し、where条件が無い場合はwhereを削除、where条件がある場合はandを追加します。
7. クエリ条件に <> または != は使用できません。
インデックス列をクエリの条件として使用する場合は、<> や != などの判定条件の使用を避ける必要があります。ビジネスで本当に必要な場合、不等号記号が使用されている場合は、インデックスの作成を再評価し、このフィールドでのインデックスの構築を避け、クエリ条件内の他のインデックス フィールドに置き換える必要があります。
8. where 条件には、複合インデックスの先頭以外の列のみが含まれます。
次のように: 複合 (ジョイント) インデックスには、key_part1、key_part2、および key_part3 の 3 つの列が含まれていますが、SQL ステートメントにはインデックスのフロント列 "key_part1" が含まれていません。MySQL のジョイント インデックスの左端の一致原則に従って、ジョイント インデックスは次のようになります。使用しないでください。
select col1 from table where key_part2=1 and key_part3=2
9. 暗黙的な型変換によりインデックスが使用されなくなります
次の SQL ステートメントは、インデックスの列の型が varchar であるため、正しくインデックスを作成できませんが、指定された値は数値であり、暗黙的な型変換が必要です。
select col1 from table where col_varchar=123;
10. order by 条件は where の条件と一致している必要があります。そうでない場合、order by は並べ替えにインデックスを使用しません。
---> 不走age索引
SELECT * FROM t order by age;
---> 走age索引
SELECT * FROM t where age > 0 order by age;
この SQL の正しい処理シーケンスは次のとおりです。
- WHERE条件と統計情報に基づいて実行計画を生成し、データを取得します。
- order by を実行するとき、データベースはまず最初のステップの実行計画をチェックして、order by のフィールドが実行計画のインデックスを使用しているかどうかを確認します。その場合は、インデックス順序を使用して、並べ替えられたデータを直接取得できます。それ以外の場合は、操作の順序を変更します。
- ソートされた結果を返す
order by (または group by、union など) のフィールドが where 条件に出現する場合にのみ、2 次並べ替えの代わりにインデックスが使用されます。
2. SELECT文の最適化について
1. 選択を避ける*
これは誰もがよく知っていることですが、なぜ select* を避ける必要があるのでしょうか? ポイントは次の 3 つです。
- 不要なカラムはデータ転送時間とネットワークのオーバーヘッドを増加させます
- varchar、text などの役に立たない大きなフィールドの場合、IO 操作が増加します。
- MySQL オプティマイザーの「インデックスのカバー」戦略の最適化が失われる可能性
- SELECT* はインデックスをカバーする可能性を排除し、MySQL オプティマイザーに基づく「インデックスをカバーする」戦略は非常に高速かつ効率的であり、業界によって推奨されています。
2. 不定の結果をもたらす関数を避ける
たとえば、now()、rand()、sysdate() などの結果が不確実な関数を使用することが容易にあり、その結果、マスター ライブラリとスレーブ ライブラリの間でデータの不整合が生じます。
3. 複数のテーブルの関連付けをクエリする場合、小さなテーブルが最初に来て、大きなテーブルが後に続きます。
MySQL では、テーブル関連付けクエリは左から右に行われ、テーブルには完全なテーブル スキャンが含まれるため、通常、スキャン効率が高くなるように小さなテーブルを前に置きます。
4. テーブルのエイリアスを使用する
複数のテーブルがある場合は、各列名の前にテーブルの別名を付けることをお勧めします。
3. DML ステートメントを最適化する
1. 大規模なバッチでデータを挿入する
insert into T values(1,2);
insert into T values(1,3);
insert into T values(1,4);
--->
Insert into T values(1,2),(1,3),(1,4);
2 番目のタイプの挿入を使用する場合、解析する必要があるのは 1 回だけです。また、SQL が短くなり、ネットワーク送信の IO も削減できます。