Mysql-SQLの追加、削除、変更の最適化
①データをまとめて挿入する
同時に多数の挿入を実行する場合は、複数の値を指定してINSERTステートメントを使用することをお勧めします(方法2)。これは、個別のINSERTステートメントを使用するよりも高速です(方法1)。一般に、バッチ挿入の効率は数倍異なります。
方法1:
insert into T values(1,2);
insert into T values(1,3);
insert into T values(1,4);
方法2:
Insert into T values(1,2),(1,3),(1,4);
後者の方法を選択する理由は3つあります。
SQLステートメントの解析操作を減らします。MySQLにはOracleのような共有プールがありません。方法2を使用すると、データは1回の解析でのみ挿入できます。
特定のシナリオでは、DB接続の数を減らすことができます。
SQLステートメントは短く、ネットワーク伝送のIOを減らすことができます。
②コミットを適切に使用する
コミットを適切に使用すると、トランザクションが占有していたリソースを解放し、消費を減らすことができます。コミット後に解放できるリソースは次のとおりです。
事务占用的 undo 数据块。
事务在 redo log 中记录的数据块。
释放事务施加的,减少锁争用影响性能。特别是在需要使用 delete 删除大量数据的时候,必须分解删除量并定期 commit。
③更新されたデータの繰り返しクエリを避ける
ビジネスに頻繁に出現し、行変更情報を取得したい行を更新する必要性に応えて、MySQLは、MySQLの変数を介して実装できるPostgreSQLのようなUPDATERETURNING構文をサポートしていません。
たとえば、レコードの行のタイムスタンプを更新し、現在のレコードに保存されているタイムスタンプを照会したい場合は、
達成する簡単な方法:
Update t1 set time=now() where col1=1;
Select time from t1 where id =1;
変数の使用は次のように書き直すことができます。
Update t1 set time=now () where col1=1 and @now: = now ();
Select @now;
前面と背面の両方で2回のネットワークラウンドトリップが必要ですが、変数を使用すると、データテーブルに再度アクセスする必要がなくなります。特に、t1テーブルに大量のデータがある場合、後者は前者よりもはるかに高速です。
④クエリの優先度または更新(挿入、更新、削除)の優先度
MySQLでは、ステートメントスケジューリングの優先度を変更することもできます。これにより、複数のクライアントからのクエリがより適切に連携して、単一のクライアントがロックのために長時間待機しないようにすることができます。優先度を変更すると、特定の種類のクエリをより高速に処理することもできます。
まず、アプリケーションの種類を判別し、アプリケーションがクエリベースか更新ベースか、クエリ効率と更新効率のどちらを確保するかを決定し、クエリ優先度と更新優先度のどちらを使用するかを決定する必要があります。
下記のスケジューリング戦略を変更する方法は、主にMyISAM、MEMROY、MERGEなどのテーブルロックのみを持つストレージエンジン用です。Innodbストレージエンジンの場合、ステートメントの実行は行ロックの順序によって決定されます。得られた。
MySQLのデフォルトのスケジューリング戦略は次のように要約できます。
書き込み操作は読み取り操作よりも優先されます。
特定のデータテーブルへの書き込み操作は、特定の時間に1回だけ実行でき、書き込み要求は到着した順序で処理されます。
特定のデータテーブルの複数の読み取り操作を同時に実行できます。
MySQLには、スケジューリング戦略を変更できるいくつかのステートメント修飾子が用意されています。
LOW_PRIORITYキーワードは、DELETE、INSERT、LOAD DATA、REPLACE、およびUPDATEに適用されます。
HIGH_PRIORITYキーワードは、SELECTステートメントとINSERTステートメントに適用されます。
DELAYEDキーワードは、INSERTステートメントとREPLACEステートメントに適用されます。
書き込み操作がLOW_PRIORITY(低優先度)要求である場合、システムはその優先度が読み取り操作よりも高いとは見なしません。
この場合、ライターの待機中に2番目のリーダーが到着すると、2番目のリーダーはライターの前に挿入できます。
ライターは、他にリーダーがいない場合にのみ操作を開始できます。この種のスケジューリングの変更により、LOW_PRIORITY書き込み操作が永久にブロックされる可能性があります。
SELECTクエリのHIGH_PRIORITY(高優先度)キーワードも同様です。これにより、通常の状況で書き込み操作の優先度が高くても、待機中の書き込み操作の前にSELECTを挿入できます。
もう1つの効果は、優先度の高いSELECTが通常のSELECTステートメントの前に実行されることです。これは、これらのステートメントが書き込み操作によってブロックされるためです。
LOW_PRIORITYオプションをサポートするすべてのステートメントをデフォルトで低優先度として処理する場合は、–low-priority-updatesオプションを使用してサーバーを起動します。
INSERTHIGH_PRIORITYを使用してINSERTステートメントを通常の書き込み優先度に上げることにより、単一のINSERTステートメントに対するこのオプションの影響を排除できます。
クエリ条件の最適化
①複雑なクエリの場合、中間一時テーブルを使用してデータを一時的に保存できます
②groupbyステートメントを最適化する
デフォルトでは、MySQLは「GROUPBY col1、col2、...;」など、GROUPBYグループのすべての値を並べ替えます。クエリメソッドは「ORDERBYcol1、col2、...;」を指定するのと同じです。 "クエリで。
同じ列を含むORDERBY句を明示的に含めると、MySQLは、ソートされていても、速度を落とすことなく最適化できます。
したがって、クエリにGROUP BYが含まれているが、グループ化された値を並べ替えたくない場合は、ORDER BYNULLを指定して並べ替えを禁止できます。
例えば:
SELECT col1, col2, COUNT(*) FROM table GROUP BY col1, col2 ORDER BY NULL ;
③結合ステートメントを最適化する
MySQLでは、SELECTステートメントを使用して、サブクエリを介して単一列のクエリ結果を作成し、この結果を別のクエリのフィルタ条件として使用できます。
サブクエリを使用すると、論理的に一度に複数のステップを完了する必要がある多くのSQL操作を完了することができます。同時に、トランザクションまたはテーブルのロックを回避でき、記述も簡単です。ただし、場合によっては、サブクエリをより効率的な結合(JOIN)に置き換えることができます。
例:注文レコードを持たないすべてのユーザーを削除するとします。次のクエリを使用して完了できます。
SELECT col1 FROM customerinfo WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )
JOIN ...を使用してこのクエリを完了すると、速度が向上します。
特に、salesinfoテーブルのCustomerIDにインデックスがある場合、パフォーマンスは向上します。クエリは次のとおりです。
SELECT col1 FROM customerinfo
LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo.CustomerID
WHERE salesinfo.CustomerID IS NULL
JOIN ...より効率的である理由は、MySQLがこの論理的な2ステップのクエリを完了するためにメモリ内に一時テーブルを作成する必要がないためです。
④ユニオンクエリを最適化する
MySQLは、一時テーブルを作成してデータを設定することにより、ユニオンクエリを実行します。重複する行を本当に削除したい場合を除いて、すべてを結合することをお勧めします。
その理由は、キーワードallがない場合、MySQLは一時テーブルに個別のオプションを追加するため、一時テーブル全体のデータが一意になり、非常にコストがかかるためです。
効率的:
SELECT COL1, COL2, COL3 FROM TABLE WHERE COL1 = 10
UNION ALL
SELECT COL1, COL2, COL3 FROM TABLE WHERE COL3= 'TEST';
非効率的な:
SELECT COL1, COL2, COL3 FROM TABLE WHERE COL1 = 10
UNION
SELECT COL1, COL2, COL3 FROM TABLE WHERE COL3= 'TEST';
⑤複雑なSQLを複数の小さなSQLに分割して、大きなトランザクションを回避します
次のように:
シンプルなSQLは、MySQLのQUERYCACHEを使用して簡単に使用できます。
ロックテーブルの時間を短縮します。特に、MyISAMストレージエンジンを使用するテーブルを短縮します。
マルチコアCPUを使用できます。
⑥削除の代わりに切り捨てを使用する
テーブル全体のレコードを削除する場合、deleteステートメントを使用した操作はundoブロックに記録され、レコードの削除もbinlogに記録されます。
当确认需要删除全表时,会产生很大量的 binlog 并占用大量的 undo 数据块,此时既没有很好的效率也占用了大量的资源。
使用 truncate 替代,不会记录可恢复的信息,数据不能被恢复。也因此使用 truncate 操作有其极少的资源占用与极快的时间。另外,使用 truncate 可以回收表的水位,使自增字段值归零。
ʻ適切なページング方法を使用してページング効率を向上させる
妥当なページング方法を使用してページングの効率を向上させるディスプレイやその他のページングのニーズについては、適切なページング方法でページングの効率を向上させることができます。
ケース1:
select * from t where thread_id = 10000 and deleted = 0
order by gmt_create asc limit 0, 15;
上記の例では、すべてのフィールドが一度にフィルター条件に従ってソートされて返されます。データアクセスオーバーヘッド=インデックスIO +すべてのインデックスレコードに対応するテーブルデータIO。
したがって、この書き込み方法をひっくり返すほど、特にテーブルデータ量が多い場合は、実行効率が悪くなり、時間が長くなります。
該当するシナリオ:中間結果セットが小さい場合(10,000行未満)、またはクエリ条件が複雑な場合(複数の異なるクエリフィールドまたはマルチテーブル結合を参照)に適用されます。
ケース2:
select t.* from (select id from t where thread_id = 10000 and deleted = 0
order by gmt_create asc limit 0, 15) a, t
where a.id = t.id;
上記の例では、tテーブルの主キーがid列であり、カバーするインデックスの副キー(thread_id、deleted、gmt_create)があることを満たしている必要があります。
ソート用のカバーインデックスを使用して、フィルター条件に基づいて主キーIDを取り出し、結合操作を実行して他のフィールドを取り出します。
データアクセスコスト=インデックスIO +テーブルデータIOに対応するインデックスページング結果(例では15行)。したがって、この書き込み方法は、最初のページをめくるのと同じように、ページをめくるたびに基本的に同じリソースと時間を消費します。
該当するシナリオ:クエリフィールドと並べ替えフィールド(つまり、where句とorder by句に含まれるフィールド)に対応するカバーインデックスがあり、中間結果セットが大きい場合に適用できます。
テーブル構築の最適化(非常に重要)
①テーブルにインデックスを作成し、whereで使用されるフィールドとorderbyを優先します。
②数値フィールド(性別、男性:1、女性:2など)を使用し、数値情報のみを文字タイプとして含むフィールドを設計しないようにしてください。これにより、クエリと接続のパフォーマンスが低下し、ストレージのオーバーヘッドが増加します。
これは、クエリと連結を処理するときに、エンジンが文字列内の各文字を1つずつ比較するためです。数値タイプの場合、1回の比較で十分です。
③大量のデータを含むテーブルをクエリすると、クエリが遅くなります。主な理由は、スキャンラインが多すぎることです。このとき、プログラム、セグメント、ページごとにクエリを実行し、トラバースをループし、結果をマージして表示することができます。
次のように、100000から100050までのデータをクエリします。
SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY ID ASC) AS rowid,* FROM infoTab)t
WHERE t.rowid > 100000 AND t.rowid <= 100050
④char/ ncharの代わりにvarchar / nvarcharを使用してください。
可変長フィールドのストレージスペースが小さいため、char / ncharの代わりにvarchar / nvarcharをできるだけ使用してください。これにより、ストレージスペースを節約できます。次に、クエリの場合、比較的小さいフィールドでの検索効率が明らかに高くなります。
NULLにスペースが必要ないとは思わないでください。例:char(100)タイプ。フィールドが作成されると、スペースは固定されます。値が挿入されているかどうかに関係なく(NULLも含まれます)、スペースは占有されます。 100文字のスペース。varcharの場合このような可変長フィールドの場合、nullはスペースを占有しません。