mySQL最適化の概要SQL書き込みの一般要件

 

SQL書き込みの一般的な要件
--- SQLステートメントは可能な限り単純です
---高い同時実行性を確保するために分解および結合し
ます
---同じデータ型の列値を比較します---インデックス付き列に対して操作を実行しません
- --SELECTを使用ない*
---負の値を回避するクエリと%プレフィックスファジークエリ
---トランザクション(接続)を短くする
--- ORをIN()に
書き換える--- ORをUNIONに書き換える
---効率的なページングを制限する
--- UNIONの代わりにUNIONALLを使用します
--- GROUP BY removesort

SQLステートメントは可能な限り単純です

l大きなSQLと複数の単純なSQL

Ø伝統的なデザインのアイデア

ØしかしMySQLは

Ø1つのSQLは1つのCPUでのみ操作できます

Ø5000以上のQPSの高い同時実行性において、1秒の大きなSQLはどういう意味ですか?

Ø1つの大きなSQLがデータベース全体をブロックする可能性があります

l大きなSQLを拒否し、複数の単純なSQLに逆アセンブルします

Ø単純なSQLキャッシュのヒット率が高い

Øロックテーブルの時間を短縮する

Ø複数のCPUを使用する

 

接続を分解して、高い同時実行性を確保します

l 3つ以上のテーブルのJOINには、高度な同時DBは推奨されません。

l接続を適切に分解して、高い同時実行性を確保します

Ø大量の初期データをキャッシュできます

Ø大きなテーブルのIDにはIN関数を使用します

Ø接続は同じテーブルを複数回参照します

l例

MySQL>タグJOINからpost_nameを選択tag_post

               tag_post.tag_id = tag.idに投稿に参加

               tag_post.post_id = post.idに

               WHERE tag.tag = '中古のおもちゃ';

MySQL>タグからtag_idを選択WHEREtag = '中古のおもちゃ';

MySQL> tag_post WHERE tag_id = 1321からpost_idを選択します。

MySQL>(123,456,314,141);のpost WHEREpost.idからpost_nameを選択します。

 

同じデータ型の列値の比較

l原則:数から数、文字から文字

l数値列と文字タイプの比較

Ø同時に倍精度に変換します

Ø比較

l文字列と数値型の比較

Ø文字列は数値に変換されます

Øインデックスクエリを使用しません

 

インデックス列に対して操作を実行しないでください

lインデックス列に対して数学演算またはデジタル演算を実行しないでください

Øインデックスは使用できません

Ø全表スキャンを発生させる

l例

 

SELECTの使用を禁止する*

l SELECT *を使用する場合

ØCPU、メモリ、IO、ネットワーク帯域幅のより多くの消費

Ø最初にデータベースからすべての列を要求し、次に不要な列を破棄しますか?

l SELECT *ではなく、必要なデータ列をフェッチするだけにしてください

Øより安全な設計:テーブル変更の影響を軽減します

Øカバーリングインデックスを使用する可能性を提供する

ØSelect/ JOINは、特にTEXT / BLOBがある場合に、ハードディスク一時テーブルの生成を減らします。

l例

SELECT * FROMタグWHEREid = 999184;

SELECTキーワードFROMタグWHEREid = 999184;

否定的なクエリと%プレフィックスファジークエリを避ける

l否定的なクエリを避ける

ØNOT、!=、<>、!<、!>、存在しない、存在しない、好きではない

l%プレフィックスファジークエリを回避する

ØB+ツリー

Øインデックスを使用できません

Ø全表スキャンにつながる

l例

 MySQL> select * from post WHERE title like '北京%';

 セットで298行(0.01秒)

 MySQL> select * from post WHERE title like '%北京%';

 セット内572行(3.27秒)

 

トランザクション(接続)を短くする

トランザクション/ DB接続を短く簡潔に保つ

Øトランザクション/接続の使用原則:開いて使用し、使い切ったら閉じる

Øロックリソースの占有を減らすために、トランザクションに関係のない操作はトランザクションの外部に配置されます

Ø一貫性を損なわないという前提の下で、長いトランザクションの代わりに複数の短いトランザクションを使用します

 

ORをIN()に書き換えます

l同じフィールドで、またはin()のように書き直します

Øまたは効率:O(n)

ØIN効率:O(Log n)

Ønが大きい場合、ORははるかに遅くなります

lINの数を制御することに注意してください。nは300未満にすることをお勧めします

l例

*をoppWHERE phone = '12347856'またはphone = '42242233'から選択します。

Select * from opp WHERE phone in( '12347856'、 '42242233');

ORをUNIONに書き換えます

l異なるフィールド、変更またはユニオンへ

Øさまざまなフィールドの「または」クエリを減らす

Øマージインデックスはしばしば非常に精神薄弱です!

l例

*をoppWHERE phone = '010-88886666'またはcellPhone = '13800138000'から選択します。

 

opp WHERE phone = '010-88886666'から*を選択します

連合

Select * from opp WHERE cellPhone = '13800138000';

 

効率的なページングを制限する(1)

l従来のページング:

Øテーブル制限10000,10から*を選択します。

lLIMIT原理:

Ø制限10000.10

Øオフセットが大きいほど、遅くなります

l推奨されるページ付け:

テーブルから*を選択WHEREid> = 23423 limit 11;#10 + 1(1ページあたり10エントリ)

select * from table WHERE id> = 23434 limit 11;

 

効率的なページングを制限する(2)

lページングモード2:

Select * from table WHERE id> =(select id from table limit 10000,1)limit 10;

lページングモード3:

SELECT * FROM table INNER JOIN(SELECT id FROM table LIMIT 10000,10)USING(id);

lページングモード4:

ØプログラムフェッチID:テーブル制限10000,10からIDを選択します。

Ø(123,456…)のテーブルWHEREidから*を選択します。

lシーンに応じてインデックスを分析および再編成する必要がある場合があります

 

効率的なページングを制限する(3)

l例

MySQL> post limit10,10からsql_no_cache *を選択します。

セットで10行(0.01秒)

MySQL> select sql_no_cache * from post limit 20000,10;

セット内10行(0.13秒)

MySQL> select sql_no_cache * from post limit 80000,10;

セットで10行(0.58秒)

MySQL>投稿制限80000,10からsql_no_cacheidを選択します。

セット内の10行(0.02秒)

MySQL> select sql_no_cache * from post WHERE id> = 323423 limit 10;

セットで10行(0.01秒)

MySQL> select * from post WHERE id> =

(post limit 80000,1からsql_no_cache idを選択します)limit 10;

セット内の10行(0.02秒)

 

UNIONの代わりにUNIONALLを使用する

l結果の重複を排除する必要がない場合は、UNIONALLを使用します

ØUNIONには重複排除のオーバーヘッドがあります

l例

MySQL> SELECT * FROM detail20091128 UNION ALL

               SELECT * FROM detail20110427 UNION ALL

               SELECT * FROM detail20110426 UNION ALL

               SELECT * FROM detail20110425 UNION ALL

               SELECT * FROM detail20110424 UNION ALL

               SELECT * FROM detail20110423;

 

GROUPBY削除ソート

lGROUPBYの実装

Øグループ

Ø自動並べ替え

l並べ替えは不要:NULLで並べ替え

l特定の順序:DESC / ASCによるグループ化

l例

MySQL>電話制限1で投稿グループからphone、count(*)を選択します。

セットの1行(2.19秒)

MySQL> select phone、count(*)from post group by phone order by null limit 1;

セット内の1行(2.02秒)

 

-------------------------------------------------- --------------

http://www.taobaodba.com/html/851_sql%E4%BC%98%E5%8C%96%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB% E7%BB%93.html SQLの最適化はDBAの日常業務に欠かせない要素です。学生の頃、ITPUBに投稿を見たことがあるのを覚えています。当時、ホストはSQLを紹介するときに式を使って彼を説明していました。最適化。SQL最適化を行うときに従うべき原則:

          T = S / V(Tは時間を表し、Sは距離を表し、Vは速度を表します)

Sは、SQLがアクセスする必要のあるリソースの合計量を示し、Vは、単位時間あたりにSQLがアクセスできるリソースの量を示します。Tは、当然、SQLの実行に必要な時間です。 SQL、式の定義に従ってそれを逆にすることができます:

  1. Sが変更されていない場合は、Vを増やしてTを減らすことができます。適切なインデックス調整により、多数の低速のランダムIOを高速のシーケンシャルIOに変換できます。サーバーのメモリを増やすことで、メモリにデータを追加すると、データをディスクに保存するよりも大幅に速度が向上します。データの保存と読み取りに電子ストレージメディアを使用するSSDは、従来の機械式ハードドライブのパフォーマンスのボトルネックを解消し、非常に高いVのストレージパフォーマンスを実現します。より高い構成のハードウェアを使用して、 Vのプロモーションの速度向上を完了します。
  2. Vが変更されていない場合、Sを減らしてTを減らすことができます。これはSQL最適化の非常に重要な部分です。Sを減らすことで、DBAが実行できることがたくさんあります。これは通常、クエリ条件で確立できます。テーブル全体を回避するための適切なインデックススキャン; SQlを書き直し、適切なプロンプトを追加してSQL実行プランを変更し、SQLが最小のスキャンパスでクエリを完了できるようにすることができます。これらのメソッドが使い果たされた場合、Nanを最適化する他のオプションはありますか?アリ部門のDBAの職務記述書に、DBAがビジネスを深く理解していることを要求する記事があります。DBAがビジネスを深く理解した後、今回はビジネスの観点から考えることができます。とDB。この時点で最適化されています。時間は半分の労力で2倍の結果を得る効果を達成できます。

ケース1:Sを下げてTを上げる

原則の紹介:
B +インデックスリーフノードの値は、インデックスフィールドに従って昇順であることがわかっています。たとえば、2つのフィールド(nick、appkey)にインデックスを付けると、インデックス内のインデックスは昇順で配置されます。 nickとappkeyの; if we現在のSQL:
select count(distinct nick)from xxxx_nickapp_09_29;は
、特定の日のログテーブルのUVをクエリしてカウントするために使用されます。オプティマイザーは、テーブルを使用してクエリを完了し、nick1から開始します。最後のnick_nがスキャンされるまでバーを下にスキャンすると、中央のプロセスが多数の繰り返しニックをスキャンします(左端の通常のスキャン)。中央の繰り返しニックをスキップできる場合、パフォーマンス多くの最適化が行われます(右端のルーズスキャン):

上記から結論を導き出すことができます:

この統計UVのSQLを右側のルーズインデックススキャンの方法でスキャンできる場合、上記のSが大幅に削減されるため、疑似ルーズインデックススキャンを実現するためにSQLを書き直す必要があります:(MySqlオプティマイザーはできませんカウントを直接最適化する(個別の列))

root @ DB 09:41:30> select count(*)from(selectdistinct(nick)from xxxx_nickapp_09_29)t;
+ ———- +
| count(*)|
+ ———- +
| 806934 |
+- -+
Sql内部クエリで、最初に異なる
ニックネームを選択し、最後に外側のカウントのレイヤーを設定すると、ニックネームの個別の値の合計を取得できます;最も重要なことはサブクエリにあります:selectdistinct(nick )上記の図を実現します。現時点でのオプティマイザの実行プランである疑似ルーズインデックススキャンは、group-byにインデックスを使用しているため、mysqlは、最初にインデックスを使用してグループ化し、次にインデックスをスキャンし、1つだけスキャンします。必要なニックネームを記録します。

実際のシナリオ:

このケースは、当社のオンライン本番システムから選択したものです。システムには、毎日大量のログデータがデータベースに保存されています。1つのテーブルの容量は10G〜50Gで、要約分析が実行されます。ログデータのuvはロジックの1つであり、Sqlは次のとおりです。

xxxx_nickapp_09_29からcount(distinct nick)を選択します。

ニックのインデックスが_xxxxサブテーブルに追加されていても、実行プランを表示すると、フルインデックススキャンになります。1つのテーブルのデータ量が多すぎるため、SQLを実行するとジッターが発生します。サーバー全体に適用され、元のSQLはルーズインデックススキャンをサポートするように書き直されました。

最適化前:

root @ DB 09:41:30> xxxx_nickapp_09_29からcount(distinct nick)を選択します。
+ ———- +
| count(*)|
+ ———- +
| 806934 |

セット内の1行(52.78秒)
SQLを1回実行するのに52.78かかります

最適化:

root @ DB 09:41:30> select count(*)from(selectdistinct(nick)from xxxx_nickapp_09_29)t;

+ ———- +
| count(*)|
+ ———- +
| 806934 |
+ ———- +
セット内の1行(5.81秒)

52.78秒から5.81秒に、速度はほぼ10倍に増加しました。

SQL実行プランを表示します。

最適化された書き込み:

root @ DB 09:41:30> Explain select count(*)from(selectdistinct(nick)from xxxx_nickapp_09_29)t;

+-+ ————- + —————————— + ——- + ————— + ——————————— + ——— +-
| id | select_type | テーブル| タイプ| possible_keys | キー| key_len | ref | 行| エクストラ|
+-+ ————- + —————————— + ——- + ————— + ——————————— + ——— +-
| 1 | シンプル| xxxx_nickapp_09_29 | 範囲| NULL | ind_nick_appkey | 67 | NULL | 2124695 |グループ化のためのインデックスの使用|
+-+ ————- + —————————— + ——- + ————— + ——————————— + ——— +-
原始写法:
root @ DB 09:41:50> xxxx_nickapp_09_29からの選択カウント(個別のニックネーム)を説明します。
+-+ ————- + —————————— + ——- + ————— + —————————- + ——— +-+ –
| id | select_type | テーブル| タイプ| possible_keys | キー| key_len | ref | 行| エクストラ|
+-+ ————- + —————————— + ——- + ————— + —————————- + ——— +-+ –
| 1 | シンプル| xxxx_nickapp_09_29 | インデックス| NULL | ind_nick_appkey | 177 | NULL | 19546123 |インデックスの使用|
+-+ ————- + —————————— + ——- + ————– + —————————- + ——— +-+ –

距離が19546123から2124695に短縮され、9分の1になっていることがわかります。^ _ ^

ケース2:増加するビジネスの書き込み特性と組み合わせて、UV統計カウントを巧みに最適化します(*)

SQLの最適化の最高レベルは、このSQLをシステムから削除できるようにすることだと思うことがありますが、いずれにせよ、これらはビジネスに対する十分な理解に基づいており、一部のビジネス製品のアップグレードまたはダウンロードを促進できます。ライン、あなたはそのようなDBAでそれを行うことができますか?

ケースを見てみましょう。アプリケーションは、データベースに毎日存在するサブテーブルの総数をカウントします。xx_01_01からcount(*)を選択します。1
つのテーブルのデータ量がどんどん大きくなるにつれて(単一テーブルは約20G)、毎回カウントします。そのとき、速度はどんどん遅くなり、同時により多くのデータページブロックをスキャンする必要があり、データベース全体のパフォーマンスのジッターにつながります。特性を分析することによって各テーブルは挿入に自己増加IDを使用し、データは削除されないため、テーブル全体の総数を回避できます。

したがって、このSQL:select count(*)from xx_01_01;次の
ように変更できます:select max(id)-min(id)+1 fromxx_01_01;
実行速度は定性的な飛躍を得ることができます^ _ ^。

ケース3:Vを増やしてTを減らす—ランダムIOVSシーケンシャルIO

            先に述べたように、Vを改善するいくつかの方法は通常、サーバーハードウェアを改善することで実現できますが、多くの中小企業にとって、比較的高いコストはまだ彼らの手の届かないところにあり、使用の成熟した経験はありません。それはまだ彼らにとって悪いことかもしれません。一般に、サーバーハードウェアに関係なく、SQLの記述が不適切で、インデックスが適切に構築されていない場合でも、SQLは機能しません。

実際のオンラインケース:コア製品ライブラリの1つは非常に多くのランダムな読み取り値を持っているので、それを読み取りライブラリと呼びましょう。1日でライブラリを読み取る負荷が非常に高いです。遅いログから、遅い日に頻繁に出現するSQLがあることがわかります。このSQLのクエリ条件は非常に複雑です。同時に、テーブル上の多くの同様のインデックス。インデックスが間違っていると思われる場合は、explainを使用してSQL実行プランを表示します。実行プランのwhereを使用すると、テーブルへのクエリが返され、多数のレコードが返されます。テーブルは多くのランダムIOをもたらします:

したがって、元のインデックスのis_detailフィールドを冗長化するだけで、インデックスをカバーし、テーブルへのクエリによるランダムioを回避し、元のランダムioをシーケンシャルioに置き換えることで、SQLを最適化できます。また、SQLの実行速度は大幅に改善されました:(次の図では、is_detailフィールドのテストが削除されます) 

要約:SQLの最適化は非常に興味深いものです。私たちの日常業務では、t = s / vのアイデアに従って最適化することができます。初めて使用するときは少し慣れていないかもしれませんが、あなたは練習を続け、要約するのが得意です。、あなたはまた、本当に素晴らしいルールを見つけるでしょう。SQLの最適化が実際のビジネスから切り離されていないことも非常に重要です。SQLの最適化に1時間費やしたかもしれませんが、最適化の結果について開発学生と話し合ったとき、開発学生はこのSQLを実際にオンラインでダウンロードできると述べました。その時は本当に笑ったり泣いたりできませんでした

おすすめ

転載: blog.csdn.net/liuming690452074/article/details/113820229