MYSQL - パフォーマンスの最適化

目次

データベースの最適化を実行する理由

mysqlデータベースの最適化

SQLとインデックスの最適化

mysql のインストールとアンインストール (Linux のオンライン インストールとアンインストール)

データベースのバージョンの選択

データの準備

テーブル構造の関係

問題のある SQL を特定する方法

スローチェックログが有効になっているかどうかを確認します。

すべてのログの変数情報を表示する

MySQL スローチェックログの保存形式

MySQLスローチェックログ解析ツール(mysqldumpslow)

導入

使用法

MySQL スロークエリログ分析ツール (pt-query-digest)

概要と機能

pt-query-digest ツールをインストールする

クイックインストール (注: wget を最初にインストールする必要があります)

インストールが完了したかどうかを確認します。

ツールの使用方法の概要:

ログをゆっくりチェックして問題のある SQL を見つける方法

SQL に多くのクエリがあり、各クエリに時間がかかる

IO 大きな SQL

インデックスミスのSQL

Explain クエリによる SQL 実行計画の分析

Explain を使用して SQL 実行計画をクエリする

各フィールドの説明:

特定の遅いクエリの最適化ケース

関数Max()の最適化

関数Count()の最適化

サブクエリの最適化

グループ化による最適化

制限クエリの最適化

インデックスの最適化


データベースの最適化を実行する理由

1. ウェブサイトのページでのアクセスエラーを回避する

        データベース接続タイムアウトによるページ 5xx エラー

        クエリが遅いためページを読み込めません

        ブロックされているためデータを送信できません

2. データベースの安定性を向上させる

        データベースの問題の多くは非効率的なクエリによって引き起こされます

3. ユーザーエクスペリエンスを最適化する

        スムーズなページアクセス速度

        優れたウェブサイト機能エクスペリエンス

mysqlデータベースの最適化

どのような観点からデータベースを最適化できますか? 以下に示すように:

1.SQLとインデックスの最適化

        要件に応じて適切な SQL を記述し、効果的なインデックスを作成します。特定の要件を達成するには、複数の方法で SQL を記述することができます。その際、最も効率的な記述方法を選択する必要があります。このとき、SQL の最適化について理解する必要があります。

2. データベーステーブル構造の最適化

        データベースのパラダイムに従ってテーブル構造を設計する テーブル構造の適切な設計は、SQL ステートメントの記述に直接関係します。

3. システム構成の最適化

        TCP 接続数の制限、開いているファイルの数の制限、セキュリティ制限など、ほとんどは Linux マシンで実行されるため、これらの構成をそれに応じて最適化する必要があります。

4. ハードウェア構成の最適化

        データベース サービス、より高速な IO、およびより多くのメモリに適した CPU を選択します。CPU が多ければ多いほど良いとは限らず、データベースのバージョンによっては最大制限があり、IO 操作によってブロッキングが軽減されるわけではありません。

注: 上の図から、ピラミッドでは、最適化のコストが下から上に向かって徐々に増加する一方、最適化の効果は徐々に減少することがわかります。

SQLとインデックスの最適化

mysql のインストールとアンインストール (Linux のオンライン インストールとアンインストール)

データベースのバージョンの選択

1. データベースのバージョンを確認する

select @@version;

データの準備

URL: https://dev.mysql.com/doc/sakila/en/sakila-installation.html

sakila-db.zip圧縮パッケージに含まれるファイルについては、以下で説明します。

データのダウンロード

手順は以下の通りです

 

テーブル構造の関係

注: このテーブル構造の関係はツールを使用して生成されます。

問題のある SQL を特定する方法

MySQL スローチェックログを開く方法と保存形式

スローチェックログが有効になっているかどうかを確認します。

show variables like 'slow_query_log'

show variables like 'slow_query_log'  

//查看是否开启慢查询日志

set global slow_query_log_file=' /usr/share/mysql/sql_log/mysql-slow.log'

//慢查询日志的位置

set global log_queries_not_using_indexes=on;

//开启慢查询日志

set global long_query_time=1;  

//大于1秒钟的数据记录到慢日志中,如果设置为默认0,则会有大量的信息存储在磁盘中,磁盘很容易满掉

すべてのログの変数情報を表示する

show variables like '%log%'

mysql> show variables like '%log%';

+-----------------------------------------+------------------------------------+

| Variable_name                           | Value                              |

+-----------------------------------------+------------------------------------+

| back_log                                | 80                                 |

| binlog_cache_size                       | 32768                              |

| binlog_checksum                         | CRC32                              |

| binlog_direct_non_transactional_updates | OFF                                |

| binlog_error_action                     | IGNORE_ERROR                       |

| binlog_format                           | STATEMENT                          |

| binlog_gtid_simple_recovery             | OFF                                |

| binlog_max_flush_queue_time             | 0                                  |

| binlog_order_commits                    | ON                                 |

| binlog_row_image                        | FULL                               |

| binlog_rows_query_log_events            | OFF                                |

| binlog_stmt_cache_size                  | 32768                              |

| binlogging_impossible_mode              | IGNORE_ERROR                       |

| expire_logs_days                        | 0                                  |

| general_log                             | OFF                                |

| general_log_file                        | /var/lib/mysql/mysql-host.log      |

| innodb_api_enable_binlog                | OFF                                |

| innodb_flush_log_at_timeout             | 1                                  |

| innodb_flush_log_at_trx_commit          | 1                                  |

| innodb_locks_unsafe_for_binlog          | OFF                                |

| innodb_log_buffer_size                  | 8388608                            |

| innodb_log_compressed_pages             | ON                                 |

| innodb_log_file_size                    | 50331648                           |

| innodb_log_files_in_group               | 2                                  |

| innodb_log_group_home_dir               | ./                                 |

| innodb_mirrored_log_groups              | 1                                  |

| innodb_online_alter_log_max_size        | 134217728                          |

| innodb_undo_logs                        | 128                                |

| log_bin                                 | OFF                                |

| log_bin_basename                        |                                    |

| log_bin_index                           |                                    |

| log_bin_trust_function_creators         | OFF                                |

| log_bin_use_v1_row_events               | OFF                                |

| log_error                               | /var/log/mysqld.log                |

| log_output                              | FILE                               |

| log_queries_not_using_indexes           | ON                                 |

| log_slave_updates                       | OFF                                |

| log_slow_admin_statements               | OFF                                |

| log_slow_slave_statements               | OFF                                |

| log_throttle_queries_not_using_indexes  | 0                                  |

| log_warnings                            | 1                                  |

| max_binlog_cache_size                   | 18446744073709547520               |

| max_binlog_size                         | 1073741824                         |

| max_binlog_stmt_cache_size              | 18446744073709547520               |

| max_relay_log_size                      | 0                                  |

| relay_log                               |                                    |

| relay_log_basename                      |                                    |

| relay_log_index                         |                                    |

| relay_log_info_file                     | relay-log.info                     |

| relay_log_info_repository               | FILE                               |

| relay_log_purge                         | ON                                 |

| relay_log_recovery                      | OFF                                |

| relay_log_space_limit                   | 0                                  |

| simplified_binlog_gtid_recovery         | OFF                                |

| slow_query_log                          | OFF                                |

| slow_query_log_file                     | /var/lib/mysql/mysql-host-slow.log |

| sql_log_bin                             | ON                                 |

| sql_log_off                             | OFF                                |

| sync_binlog                             | 0                                  |

| sync_relay_log                          | 10000                              |

| sync_relay_log_info                     | 10000                              |

+-----------------------------------------+------------------------------------+

61 rows in set (0.01 sec)

スローチェックログを有効にする:

show variables like 'slow_query_log'  
//查看是否开启慢查询日志
set global slow_query_log_file=' /var/lib/mysql/mysql-host-slow.log '
//慢查询日志的位置
set global log_queries_not_using_indexes=on;
//开启慢查询日志
set global long_query_time=1;  
//大于1秒钟的数据记录到慢日志中,如果设置为默认0,则会有大量的信息存储在磁盘中,磁盘很容易满掉

スロークエリログが有効になっているかどうかを確認します。

mysqlの操作では、

show databases;
use sakila;
select * from store;
select * from staff;

ログ ファイルを監視して、ログ ファイルが書き込まれているかどうかを確認します。

tail -50f /var/lib/mysql/mysql-host-slow.log

MySQL スローチェックログの保存形式

以下に示すように:

例証します:

1. # 時間: 180526 1:06:54 ------->クエリ実行時間

2. # User@Host: root[root] @ localhost [] Id: 4 ------->SQLを実行するホスト情報

3. # Query_time: 0.000401 Lock_time: 0.000105 Rows_sent: 2 Rows_examined: 2------>SQL 実行情報:

Query_time: SQL クエリ時間

Lock_time: ロック時間

Rows_sent: 送信された行数

Rows_examined: ロックによってスキャンされた行の数

4. SET timestamp=1527268014; ------->SQL 実行時間

5. select * from Staff; ------->SQL実行内容

MySQL スローチェックログ分析ツール( mysqldumpslow )

導入

        スロー クエリ ログを表示するにはどうすればよいですか? スロー クエリ ログがオンになっている場合、大量のデータが生成されます。その後、ログを分析し、分析レポートを生成し、レポートを通じて最適化することができます。

使用法

次に、このツールの使用法を確認してみましょう。

注: mysql >コマンドラインではなく、mysql データベースが配置されているサーバー上で

このツールの使用方法:

mysqldumpslow -h 

詳細情報を表示する

Mysqldump遅い -v

上位 10 件の低速クエリ ログを表示します。mysqldumpslow 分析の結果は次のとおりです。

mysqldumpslow -t 10 /var/lib/mysql/mysql-slow.log

上の 2 つの図は分析の結果で、それぞれの結果には、実行時間、ロック時間、送信行数、スキャン行数が表示されます。

このツールは最も一般的に使用されるツールであり、mysql をインストールすることによってインストールされますが、このツールの統計結果は比較的少なく、最適化ロックのパフォーマンスに関するデータはまだ比較的少ないです。

MySQL スロークエリログ分析ツール (pt-query-digest)

概要と機能

        優秀な MySQL DBA として、いくつかの便利な MySQL 管理ツールをマスターする必要もあります。そのため、私は MySQL の管理を容易にするいくつかのツールを整理して探してきました。次の期間では、エネルギーの大部分がこれらのツールの検索に費やされることになります。

        パフォーマンス管理は常に最優先事項です。DBA の多くのタスクの管理では、その価値が見えず、測定する方法もありません。しかし、システムがカタツムリのように遅い場合、DBA は監視を通じてシステムを崩壊の危機から回復することができます。高速鉄道の時代に戻りましょう。その価値と感触は非常に大きいはずです。(多くの企業リーダーは、システムが動作しなくなったら、より高速な CPU、より大きなメモリ、およびより高速なストレージに置き換える必要があると考えており、これは少数派ではありません。したがって、DBA の価値は反映されていません。給料は当然ありません。非常に高額になります)

        mysql ログは、mysql のパフォーマンス ボトルネックを追跡する最も速く、最も直接的な方法です。システム パフォーマンスのボトルネックが発生した場合は、まずスロー クエリ ログを開いて追跡する必要があります。この期間中、スロー クエリ ログの管理と表示は行われてきました。この記事を読んだ後、スロー クエリ ログを表示するための別のツールを偶然発見しました: mk-query-digest. このツールは、MySQL DBA がインターネット上でマスターしなければならないツールのトップ 10 として知られています。

pt-query-digestツールをインストールする

クイックインストール (注: wget を最初にインストールする必要があります)

wget https://www.percona.com/downloads/percona-toolkit/2.2.16/RPM/percona-toolkit-2.2.16-1.noarch.rpm && yum localinstall -y percona-toolkit-2.2.16-1 .norch.rpm

インストールが完了したかどうかを確認します

 コマンドラインに「pt-summary」と入力します。

以下のように表示されます。インストールは成功しました。[[root@node03 mysql]# pt-query-digest --help] と入力します。 

ツールの使用方法の概要:

pt-summary –ヘルプ

wget http://percona.com/get/pt-summary

サーバー情報の表示

コマンド: pt-summary

ディスク オーバーヘッドの使用状況情報を表示する

コマンド: pt-diskstats

mysqlデータベース情報の表示

命令:pt-mysql-summary --user=root --password=123456

スロークエリログを分析する

コマンド: pt-query-digest /data/mysql/data/db-3-12-slow.lo

mysqlのスレーブデータベースと同期ステータスを検索します。

命令:pt-slave-find --host=localhost --user=root --password=123456

mysql デッドロック情報の表示

pt-deadlock-logger --user=root --password=123456 localhost

スロークエリログからインデックスの使用状況を分析する

pt-index-usage low_20131009.log

データベーステーブル内の重複したインデックスを検索する

pt-duplicate-key-checker --host=localhost --user=root --password=123456

mysql テーブルとファイルの現在アクティブな IO オーバーヘッドを表示する

pt-ioprofile

さまざまな mysql 設定ファイル間の違いを表示する

pt-config-diff /etc/my.cnf /etc/my_master.cnf

pt-find は mysql テーブルを検索し、コマンドを実行します。例は次のとおりです。

データベース内で 2G を超えるテーブルを検索します。

pt-find --user=root --password=123456 --tablesize +2G

MyISAM エンジンで 10 日前に作成されたテーブルを見つけます。

pt-find --user=root --password=123456 --ctime +10 --engine MyISAM

テーブルとインデックスのサイズを表示し、並べ替える

pt-find --user=root --password=123456 --printf "%T\t%D.%N\n" | ソート -rn

pt-kill は、標準を満たす mysql プロセスを強制終了します。

60 秒以上かかるクエリを表示する

pt-kill --user=root --password=123456 --busy-time 60 --print

60 秒を超えるクエリを強制終了する

 pt-kill --user=root --password=123456 --busy-time 60 --kill

mysql認証を表示する

1 pt-show-grants --user=root --password=123456

2 pt-show-grants --user=root --password=123456 --special –revoke

データベース複製の整合性を検証する

pt-table-checksum --user=root --password=123456

付録:

ログをゆっくりチェックして問題のあるSQLを見つける方法

SQL に多くのクエリがあり、各クエリに時間がかかる

        通常、それは pt-query-digest によって分析される最初のいくつかのクエリです。このツールでは、実行された各 SQL の数と割合を明確に確認できます。より多くの回数実行され、より大きな割合を占める SQL

IO 大きな SQL

        pt-query-digest 分析の行検査項目に注目してください。スキャンされる行が多いほど、IO も大きくなります。

インデックスミスのSQL

        pt-query-digest 分析における Rows Exam と Rows Send の比較に注目してください。これは、この SQL のインデックス ヒット率が高くないことを意味します。この種の SQL には特に注意する必要があります。

Explain クエリによるSQL 実行計画の分析

Explain を使用して SQL 実行計画をクエリする

SQLの実行計画はSQLの実行効率を反映するもので、具体的な実行方法は以下のとおりです。

実行される SQL の前に Explain キーワードを追加するだけです。

各フィールドの説明:

1) id 列の数値が大きいほど高速に実行されます。数値が同じ場合は上から下に実行されます。id 列が null の場合、これは結果セットであることを意味しますクエリに使用する必要はありません。

2) 一般的な select_type 列には次のものがあります。

A: simple: ユニオン演算を必要としない、またはサブクエリを含まない単純な選択クエリを示します。接続クエリがある場合、外側のクエリは単純であり、クエリは 1 つだけです。

B: プライマリ: ユニオン操作が必要な選択、またはサブクエリを含む選択。最も外側のユニット クエリの select_type はプライマリです。そして1つだけ

C: Union: 2 つの選択クエリを Union で接続します。最初のクエリは派生テーブルです。最初のテーブルを除き、2 番目以降のテーブルの select_type は Union です。

D: 依存ユニオン: Union と同じで、union または Union all ステートメントに表示されますが、このクエリは外部クエリの影響を受けます。

E: Union result: Union を含む結果セット Union および Union all ステートメントでは、クエリに参加する必要がないため、id フィールドは null になります。

F: サブクエリ: from 句に含まれるサブクエリを除き、他の場所に出現するサブクエリはサブクエリである可能性があります。

G: 依存サブクエリ: 依存ユニオンに似ており、このサブクエリのクエリが外部テーブル クエリの影響を受けることを示します。

H: 派生: from 句に出現するサブクエリは派生テーブルとも呼ばれ、他のデータベースではインライン ビューまたはネストされた選択と呼ばれることもあります。

3)テーブル

表示されるクエリ テーブル名。クエリで別名が使用されている場合は、別名がここに表示されます。データ テーブルの操作に関係しない場合は、null として表示されます。<derived N> で囲まれて表示される場合は、山括弧は、これが一時テーブルであることを意味します。次の N は実行プランの ID で、結果がこのクエリからのものであることを示します。山括弧で囲まれた <union M,N> の場合、それは <derived N> に似ており、一時テーブルでもあり、結果がユニオン クエリの ID M,N を持つ結果セットから取得されたものであることを示します。

4)タイプ

最良から最悪の順: system、const、eq_ref、ref、fulltext、ref_or_null、unique_subquery、index_subquery、range、index_merge、index、ALL、すべてを除く、その他の型はインデックスを使用できます (index_merge、other を除く)。タイプ

A: システム: テーブル内にデータが 1 行しかないか、空のテーブルであり、myisam テーブルとメモリ テーブルにのみ使用できます。Innodb エンジン テーブルの場合、この場合のタイプ列は通常、all またはインデックスです。

B: const: 一意のインデックスまたは主キーを使用する場合、返されるレコードは 1 行のレコードの where 条件と同等である必要があります。通常、型は const です。他のデータベースはユニーク インデックス スキャンとも呼ばれます

C: eq_ref: 2 つのテーブルに接続されるクエリ プランに表示されます。ドライバー テーブルは 1 行のデータのみを返します。このデータ行は 2 番目のテーブルの主キーまたは一意のインデックスであり、null であってはなりません。一意のインデックスと主キーは複数の列です。eq_ref は、すべての列が比較に使用される場合にのみ表示されます。

D: ref: eq_ref のような接続順序を必要とせず、主キーや一意のインデックスも必要とせず、検索に等条件が使用され、補助インデックスを使用した等価検索が一般的であれば発生する可能性があります。または、複数列の主キーまたは一意のインデックスで、最初の列以外の列を等値検索として使用することも発生する可能性があり、つまり、返されるデータが一意でない場合に等値検索が発生する可能性があります。

E: fulltext: 全文インデックスの取得。全文インデックスの優先度が非常に高いことに注意してください。全文インデックスと通常のインデックスが同時に存在する場合、mysql は全文インデックスを優先します。コストに関係なくインデックスを作成します。

F: ref_or_null: null 値の比較が追加されることを除いて、ref メソッドに似ています。実際にはあまり使われていません。

G: unique_subquery: where の形式内サブクエリに使用され、サブクエリは重複する値を含まない一意の値を返します。

H:index_subquery: 補助インデックスまたは定数リストを使用する形式のサブクエリに使用されます。サブクエリは重複した値を返す可能性があり、インデックスを使用してサブクエリの重複を排除できます。

I: range: インデックス範囲スキャン。>、<、is null、 between、in、like などの演算子を使用したクエリでよく使用されます。

J:index_merge: クエリが 3 つ以上のインデックスを使用し、最後に交差または共用体を取得することを示します。共通の and and or 条件は異なるインデックスを使用します。正式な並べ替えは ref_or_null の後にありますが、実際には、すべてのインデックスを読み取る必要があるため、ほとんどの場合、パフォーマンスは範囲ほど良くない可能性があります

K: インデックス: インデックス フル テーブル スキャン、最初から最後までインデックスをスキャンします。データ ファイルを読み取る必要のないクエリを処理するにはインデックス列を使用し、インデックス ソートまたはグループ化クエリを使用するのが一般的です。

L: all: これは、テーブル全体のデータ ファイルをスキャンし、サーバー層でフィルター処理して、要件を満たすレコードを返します。

5)可能なキー

クエリで使用される可能性のあるインデックスがここにリストされます。

6)キー

実際に使用されているインデックスをクエリします。select_type が Index_merge の場合、ここには 2 つ以上のインデックスが表示されます。その他の select_type の場合、ここには 1 つだけ表示されます。

7) key_len

クエリの処理に使用されるインデックスの長さ。単一列インデックスの場合、インデックス全体の長さが含まれます。複数列インデックスの場合、クエリですべての列を使用できない場合があります。具体的には、列の数です。インデックスが使用されている場合、ここで計算されます。未使用の列はここでは計算されません。この列の値に注意し、複数列インデックスの合計長を計算して、すべての列が使用されているかどうかを確認してください。mysql の ICP 機能で使用されるインデックスはカウントされないことに注意してください。また、key_len は where 条件で使用されるインデックスの長さのみを計算し、ソートやグループ化でインデックスが使用されても key_len では計算されません。

8)参照

定数と同等のクエリの場合は、ここに const が表示されます。接続クエリの場合、駆動テーブルの実行プランには、駆動テーブルの関連フィールドが表示されます。条件に式または関数が使用されている場合、または条件が使用されている場合は、列に内部エラーがあります。暗黙的な変換。ここでは func として表示される場合があります。

9)行

これは実行計画のスキャンラインの推定数であり、正確な値ではありません。

10)おまけ

この列には多くの情報を表示できます。情報は数十あります。一般的に使用される情報は次のとおりです。

A:distinct:選択部分でdistinctキーワードが使用されています

B: テーブルは使用されていません: from 句を使用しないクエリまたは From デュアルクエリ

C: not in() 形式のサブクエリ、または notexists 演算子の結合クエリを使用します。これはアンチ結合と呼ばれます。つまり、一般的な結合クエリは最初に内部テーブルをクエリし、次に外部テーブルをクエリしますが、アンチ結合クエリは最初に外部テーブルをクエリし、次に内部テーブルをクエリします。

D: using filesort: ソート時にインデックスが使用できない場合に発生します。order by ステートメントと group by ステートメントでよく見られます。

E: インデックスを使用: クエリ時にテーブルにクエリを返す必要はなく、クエリされたデータはインデックスを通じて直接取得できます。

F: 結合バッファーの使用 (ブロック ネスト ループ)、結合バッファーの使用 (バッチ キー アクセス): 5.6.x 以降のバージョンでは、関連するクエリの BNL および BKA 機能が最適化されています。主な目的は、内部テーブルのループ数を減らし、クエリを順番にスキャンすることです。

G:sort_unionを使用する、using_union、intersectを使用する、sort_intersectionを使用する:

using intersect: 各インデックスの条件をandで表現した場合に、処理結果から交差を求めることを示します。

using Union:各インデックスの条件を or で結合する際に、処理結果から和集合を求めることを示します。

using sort_union と using sort_intersection: は、前の 2 つと似ていますが、大量の情報をクエリするために and と or を使用するときに表示される点が異なります。最初に主キーがクエリされ、次にレコードが読み取られ、並べ替えとマージの後に返されます。

H: 一時テーブルを使用: 中間結果を格納するために一時テーブルが使用されることを示します。一時テーブルには、メモリ一時テーブルとディスク一時テーブルがあります。これらは実行プランでは表示されません。これらを確認するには、ステータス変数 used_tmp_table および used_tmp_disk_table をチェックする必要があります。

I: where: を使用すると、ストレージ エンジンから返されたすべてのレコードがクエリ条件を満たしているわけではなく、サーバー層でフィルターする必要があることを示します。クエリ条件は制限条件と検査条件に分かれており、5.6 より前では、ストレージ エンジンは制限条件に従ってデータをスキャンして返すことしかできず、その後、サーバー層が検査条件に従ってフィルタリングして、クエリに真に一致するデータを返しました。5.6.x 以降、ICP 機能がサポートされ、チェック条件をストレージ エンジン層にプッシュダウンできるようになり、チェック条件や制限を満たさないデータは直接読み取られなくなり、スキャンされるレコード数が大幅に削減されます。ストレージエンジン。追加の列はインデックス条件の使用を示します

J: firstmatch(tb_name): 5.6.x で導入されたサブクエリを最適化する新機能の 1 つで、where 句に in() 型を含むサブクエリで一般的です。内部テーブルのデータ量が比較的多い場合、これが発生する可能性があります。

K: loosescan(m..n): 5.6.x 以降に導入されたサブクエリを最適化する新機能の 1 つ。in() タイプのサブクエリでは、サブクエリが重複レコードを返すときにこの問題が発生することがあります。

これらに加えて、多くのクエリ データ ディクショナリ ライブラリがあり、実行計画のプロセス中に、結果が存在しないことを示すプロンプト メッセージがいくつか見つかります。

11)フィルタリング済み

この列は、Explain Extended を使用するときに表示されます。5.7 以降のバージョンにはデフォルトでこのフィールドがあるため、Explain Extended を使用する必要はありません。このフィールドは、ストレージ エンジンから返されたデータがサーバー層でフィルタリングされた後、クエリを満たす残りのレコードの割合を示します。これは特定のレコード数ではなくパーセンテージであることに注意してください。

添付写真:

特定の遅いクエリの最適化ケース

関数Max()の最適化

目的: 最終支払い時刻のクエリ - max() 関数の最適化

声明:

select max(payment_date) from payment;

実行計画:

explain select max(payment_date) from payment;


表示された実行プランはあまり効率的ではなく、サーバーの効率が低下する可能性があることがわかります。どうすれば最適化できますか?

インデックスの作成

create index inx_paydate on payment(payment_date);

インデックスはシーケンシャルに操作され、テーブルをスキャンする必要がないため、実行効率は比較的一定になります。

関数Count()の最適化

要件: 2006 年と 2007 年の映画の数を 1 つの SQL で同時に確認する

間違った方法:

声明:

select count(release_year='2006' or release_year='2007') from film;

2006 年と 2007 年の数字はわかりません。

 select count(*) from film where release_year='2006' or release_year='2007';

正しい書き方:

select count(release_year='2006' or null) as '06films',count(release_year='2007' or null) as '07films' from film;

違い: count(*) と count(id)

テーブルを作成してステートメントを挿入する

 create table t(id int);

 insert into t values(1),(2),(null);

Count(*):select count(*)from t;

Count(id):select count(id)from t;

例証します:

Count(id) は null を含まない値です

Count(*) は null を含む値です

サブクエリの最適化

        サブクエリは開発プロセスでよく使用される手法です。通常、サブクエリは結合クエリに最適化する必要があります。ただし、最適化の際には、関連付けられたキーが 1 対多の関係にあるかどうかに注意する必要があります、重複データに注意してください。

作成した t テーブルを表示します

show create table t;

次に t1 テーブルを作成します

create table t1(tid int);

データを挿入します

サブクエリを実行する必要があります。要件は、テーブル t1 の tid にある ID を持つテーブル t 内のすべてのデータをクエリすることです。

select * from t where t.id in (select t1.tid from t1);

次に、結合操作を使用して操作を実行します。

select id from t join t1 on t.id =t1.tid;

 上記の結果から判断すると、クエリ結果は一貫しているため、サブクエリを結合操作に最適化します。

次に、別のデータを t1 テーブルに挿入します。

insert into t1 values (1);

select * from t1;

この場合、サブクエリを使用してクエリを実行すると、返される結果は次のようになります。

join メソッドを使用して検索すると、次の図のようになります。

この場合、1 対多の関係があり、データの重複が発生するため、データの重複を避けるために、distinct キーワードを使用して重複排除操作を実行する必要があります。

select distinct id from t join t1 on t.id =t1.tid;

注: この 1 対多の関係は、開発プロセス中に遭遇した落とし穴です。データの重複が発生するため、全員が注意する必要があります。

例: サンドラが主演するすべての映画をクエリします:

explain select title,release_year,length

 from film

 where film_id in (

 select film_id from film_actor where actor_id in (

 select actor_id from actor where first_name='sandra'));

グループ化による最適化

同じテーブルの列を使用する方が良いですが、

要件: 各俳優が参加した映画の数 - (映画リストとキャストリスト) 

explain select actor.first_name,actor.last_name,count(*)

from sakila.film_actor

inner join sakila.actor using(actor_id)

group by film_actor.actor_id;

最適化された SQL:

explain select actor.first_name,actor.last_name,c.cnt

from sakila.actor inner join (

select actor_id,count(*) as cnt from sakila.film_actor group by actor_id

)as c using(actor_id);

注: 上記の実行計画から判断すると、この最適化されたメソッドは一時ファイルとファイルの並べ替えを使用せず、代わりにインデックスを使用します。クエリ効率は非常に高いです。

現時点では、テーブル内のデータが比較的大きいため、多くの IO 操作が占有され、SQL 実行の効率が最適化され、サーバー リソースが節約されるため、最適化する必要があります。

知らせ:

1. mysql における using キーワードの役割: つまり、 using を使用するには、テーブル a とテーブル b に同じ列が必要です

2. Joinを使用して複数のテーブルに対して結合クエリを実行する場合、通常は On を使用して 2 つのテーブル間の関係を確立します。実際には、Using というもっと便利なキーワードがあります。

3. 2 つのテーブルに関連付けられたフィールド名が同じ場合は、Using を使用して関係を確立できます。これは簡潔かつ明確です。

制限クエリの最適化

Limit はページング処理によく使用され、duration は order by 句で使用されるため、ほとんどの場合 Filesorts が使用され、多くの IO 問題が発生します。

例:

条件:ムービーIDと説明情報をクエリし、テーマごとにソートし、シリアル番号50から5個のデータを取得します。

select film_id,description from sakila.film order by title limit 50,5;

実行結果:

その実行計画を確認してください。

 この操作にはどのような最適化方法を使用する必要がありますか?

最適化ステップ 1:

ご存知のとおり、innodb は主キーの論理順序に従ってソートされるため、インデックス付きカラムまたは主キーを使用して order by 操作を実行します。多くの IO 操作を回避できます。

select film_id,description from sakila.film order by film_id limit 50,5;

 実行計画を確認する

 それでは、行 500 から始まる 5 つのレコードを取得した場合、実行計画はどのようになりますか?

explain select film_id,description from sakila.film order by film_id limit 500,5\G

ページをめくるほど IO 操作が大きくなり、テーブルに数千万行のデータがある場合、ページめくりがどんどん遅くなるため、さらに最適化する必要があります。

最適化ステップ 2: 前回返された主キーを記録し、次のクエリで主キー フィルタリングを使用します。(注: これにより、データ量が大きい場合に多くのレコードをスキャンすることが回避されます)

最後の制限は 50,5 でした。そのため、この最適化プロセスでは最後のインデックス レコード値を使用する必要があります。

select film_id,description from sakila.film  where film_id >55 and film_id<=60 order by film_id limit 1,5;

実行計画を表示します。

 結論:走査線の数は変化せず、実行計画は非常に固定されており、効率も非常に固定されています。

予防:

主キーは順番に並べ替える必要があります。主キーの中央に特定の列または複数の列がある場合、リストされるデータは 5 行未満になります。連続していない場合は、追加の列 Index_id を作成して、この列のデータを自動的に増やしたい場合は、インデックスを追加するだけです。

インデックスの最適化

1.インデックスとは何ですか?

索引は本の目次に相当し、目次のページ番号をもとに必要な内容をすぐに見つけることができます。

データベースはインデックスを使用して特定の値を検索し、前方をポイントしてその値を含む行を検索します。テーブルにインデックスを作成し、インデックス内でクエリ条件を満たすインデックス値を検索し、最後にインデックスに保存された ROWID (ページ番号に相当) を介してテーブル内の対応するレコードをすばやく検索します。インデックスの確立は、テーブル内の比較的方向性のあるフィールドであり、ディレクトリに相当します。たとえば、行政区域コードです。同じ地域内の行政区域コードはすべて同じです。次に、この列にインデックスを追加します。スキャンの繰り返しを避け、最適化の目的を達成してください。

2. インデックスの作成方法

インデックスは、CREATE TABLE ステートメントの実行時に作成できます。また、CREATE INDEX または ALTER TABLE を単独で使用してテーブルにインデックスを追加することもできます。

1 テーブルの変更

ALTER TABLE は、通常のインデックス、UNIQUE インデックス、または PRIMARY KEY インデックスを作成するために使用されます。

ALTER TABLE table_name ADD INDEX index_name (column_list)

ALTER TABLE table_name ADD UNIQUE (column_list)

ALTER TABLE table_name ADD PRIMARY KEY (column_list)

注: table_name はインデックスを作成するテーブルの名前、column_list はインデックスを作成する列を示します。複数の列がある場合は、カンマで区切ります。インデックス名index_nameはオプションで、デフォルトでは、MySQLは最初のインデックス列に基づいて名前を割り当てます。さらに、ALTER TABLE を使用すると、単一のステートメントで複数のテーブルを変更できるため、複数のインデックスを同時に作成できます。

2 インデックスの作成

CREATE INDEX は、テーブルに通常のインデックスまたは UNIQUE インデックスを追加できます。

CREATE INDEX index_name ON table_name (column_list)

CREATE UNIQUE INDEX index_name ON table_name (column_list)

注: table_name、index_name、column_list は ALTER TABLE ステートメントと同じ意味を持ち、インデックス名はオプションではありません。また、CREATE INDEX ステートメントを使用して PRIMARY KEY インデックスを作成することはできません。

3.インデックスの種類

インデックスを作成するときに、インデックスに重複値を含めることができるかどうかを指定できます。含めない場合は、インデックスをPRIMARY KEY または UNIQUE インデックスとして作成する必要があります。単一列の一意のインデックスの場合、これにより、単一列に重複した値が含まれないことが保証されます。複数列の一意のインデックスの場合、複数の値の組み合わせが繰り返されないことが保証されます。

PRIMARY KEY インデックスは UNIQUE インデックスと非常によく似ています。

実際、PRIMARY KEY インデックスは PRIMARY という名前の単なる UNIQUE インデックスです。これは、テーブル内に同じ名前のインデックスを 2 つ持つことは不可能であるため、テーブルには PRIMARY KEY を 1 つだけ含めることができることを意味します。

次のSQL ステートメントは、sid の PRIMARY KEY インデックスを Students テーブルに追加します。

ALTER TABLE students ADD PRIMARY KEY (sid)

4.インデックスの削除

インデックスは、 ALTER TABLE または DROP INDEX ステートメントを使用して削除できます。CREATE INDEX ステートメントと同様に、DROP INDEX は ALTER TABLE 内のステートメントとして処理できます。構文は次のとおりです。
 

DROP INDEX index_name ON talbe_name

ALTER TABLE table_name DROP INDEX index_name

ALTER TABLE table_name DROP PRIMARY KEY

このうち、最初の 2 つのステートメントは同等であり、table_name 内のインデックスindex_name が削除されます。

3番目のステートメントは、PRIMARY KEY インデックスを削除する場合にのみ使用されます。これは、テーブルには PRIMARY KEY インデックスが 1 つしか存在できないため、インデックス名を指定する必要がありません。PRIMARY KEY インデックスが作成されていないが、テーブルに 1 つ以上の UNIQUE インデックスがある場合、MySQL は最初の UNIQUE インデックスを削除します。

テーブルから列が削除されると、インデックスが影響を受けます。複数列インデックスの場合、列の 1 つが削除されると、その列もインデックスから削除されます。インデックスを構成するすべての列を削除すると、インデックス全体が削除されます。

   5.インデックスを表示する

show index from tblname;

show keys from tblname;

   6.インデックスはどのような状況で使用されますか?

1. テーブルの主キー

2.一意のインデックスを自動的に作成します

3. テーブルフィールドの一意の制約

4. 直接条件付きクエリのフィールド (SQL の条件付き制約に使用されるフィールド)

5. クエリ内の他のテーブルに関連付けられたフィールド

6. クエリ内の並べ替えられたフィールド (並べ替えられたフィールドにインデックスを介してアクセスすると、並べ替え速度が大幅に向上します)

7. クエリ内の統計またはグループ統計のフィールド

8. テーブルのレコードが少なすぎます (テーブルに 5 つのレコードしかなく、インデックスを使用してレコードにアクセスする場合、最初にインデックス テーブルにアクセスし、次にインデックス テーブルを介してデータ テーブルにアクセスする必要があります。一般に、インデックス テーブルとデータ テーブルは同じデータ ブロック内にありません)

9. 頻繁に挿入、削除、または変更されるテーブル (頻繁に処理される一部のビジネス テーブルでは、クエリが許可する場合はインデックスを可能な限り削減する必要があります)

10. データが繰り返され均等に分布するテーブル フィールド (テーブルに 100,000 行のレコードがあり、T と F の 2 つの値のみを持つフィールド A があり、各値の分布確率が約 50% である場合、この種のテーブル A フィールドにインデックスを構築しても、通常、データベースのクエリ速度は向上しません。)

11. メイン フィールドと一緒にクエリされることが多いが、メイン フィールドのインデックス値が多数あるテーブル フィールド

12. 数千万の MySQL データベースのインデックスを作成するときにすべきこととパフォーマンスを向上させる方法

3.インデックスを作成するために適切な列を選択する方法

1. where 句、group  by 句、order by 句、および on 句の 列にインデックスを追加します。

2.インデックスフィールドは小さいほど良いです(データベースのデータストレージユニットは「ページ」に基づいているため、より多くのデータが格納され、IOが大きくなります)

3. 分散の大きい列がジョイントインデックスの前に配置されます。

例:

select * from payment where staff_id =2 and customer_id =584;

知らせ:

インデックス ( Staff_id customer_id ) の方が良いですか、それともインデックス ( customer_id Staff_id ) の方が良いですか?

では、分散をどのように検証するのでしょうか?

A.まずテーブル構造を見てみましょう

desc payment;

B.これら 2 つのフィールドの異なる ID の数をそれぞれ確認します。数が大きいほど分散の程度が大きくなります。したがって、次の図からわかるように、customer_id の分散の程度が大きくなります。

結論: customer_id は非常に離散的であるため、インデックス ( customer_id Staff_id )を使用する方が良いです。

C. mysql ジョイント インデックス

①命名規則:テーブル名_フィールド名

1. インデックスを作成する必要があるフィールドは、where 条件内にある必要があります。

2. データ量が少ないフィールドにはインデックスを付ける必要はありません。

3. where 条件に OR 関係がある場合、インデックスは機能しません。

4. 一番左の原則を遵守する

ジョイントインデックスとは何ですか?

  1. 2 つ以上の列のインデックスは結合インデックスと呼ばれ、複合インデックスとも呼ばれます。
  2. インデックスに追加の列を使用すると、検索範囲を狭めることができますが、2 つの列を持つインデックスを使用することは、 2 つの別々のインデックスを使用することとは異なります。複合インデックスの構造は電話帳に似ており、人の名前は姓と名で構成されます。電話帳はまず姓のペアで並べ替えられ、次に同じ姓を持つ人を名で並べ替えます。 。電話帳は、姓がわかっている場合には非常に便利で、姓と名の両方がわかっている場合はさらに役立ちますが、姓のみで姓がわからない場合は役に立ちません。

したがって、複合インデックスを作成するときは、列の順序を慎重に考慮する必要があります。複合インデックスは、インデックス内のすべての列を検索する場合、または最初の数列のみを検索する場合に役立ちますが、後続の列を検索する場合には役に立ちません。

4.インデックス最適化SQLの手法

1. インデックスの保守と最適化 (インデックスの重複と冗長化)

インデックスを増やすとクエリの効率が向上しますが、挿入、更新、および削除の効率は低下します。ただし、実際にはそうでないこともよくあります。インデックスが多すぎると、使用効率が低下するだけでなく、クエリの効率にも影響します。これは、クエリの効率に影響します。これはデータベース クエリによるものです。分析するときは、まずクエリに使用するインデックスを選択する必要があります。インデックスが多すぎると、分析プロセスが遅くなり、クエリの効率も低下します。したがって、次のことを知る必要があります。不要なものを増やしたり、時には維持したり、削除したりする方法。

2. 重複したインデックスや冗長なインデックスを見つける方法

重複したインデックス:

重複インデックスとは、同じ列に同じ順序で構築された同じタイプのインデックスを指します。次の表の主キー列と ID 列のインデックスが重複インデックスです。

create table test(

id int not null primary key,

name varchar(10) not null,

title varchar(50) not null,

unique(id)

)engine=innodb;

冗長インデックス:

冗長インデックスとは、複数のインデックスで同じプレフィックス列を持つインデックス、または結合インデックスの主キーを含むインデックスを指します。次の例では、key (name, id) が冗長インデックスです。

create table test(

id int not null primary key,

name varchar(10) not null,

title varchar(50) not null,

key(name,id)

)engine=innodb;

注: innodb の場合、実際には各インデックスの後ろに主キーが含まれますが、このとき、人為的に作成した結合インデックスには主キーが含まれているため、現時点では冗長インデックスとなります。

3. 重複したインデックスを見つける方法

ツール: pt-duplicate-key-checker ツールを使用して、重複インデックスや冗長インデックスをチェックします。

pt-重複キーチェッカー -uroot -padmin -h 127.0.0.1

4. インデックスのメンテナンス方法

ビジネスの変化により、一部のインデックスは不要になったため、削除する必要があります。

mysql では、インデックスの使用状況はスロー クエリ ログと pt-index-usage ツールを通じてのみ分析できます。

pt-index-usage -uroot -padmin /var/lib/mysql/mysql-host-slow.lo

 添付: https://www.percona.com/downloads/

5.注意事項

適切に設計されたMySql インデックスにより、データベースが高速化され、データベースの効率が大幅に向上します。MySql インデックスを設計するときに注意すべき点がいくつかあります。

1. インデックスを作成する

クエリが大半を占めるアプリケーションでは、インデックスが特に重要です。多くの場合、パフォーマンスの問題は、単にインデックスの追加を忘れたり、より効果的なインデックスを追加しなかったりすることが原因で発生します。インデックスがない場合、特定のデータでも検索するためにテーブル全体のスキャンが実行されます。テーブル内のデータ量が多く、条件を満たす結果がほとんどない場合、インデックスを追加しないと致命的なパフォーマンスの低下が発生します。 . .

ただし、あらゆる状況でインデックスを作成する必要はありません。たとえば、性別には 2 つの値しかない場合があります。インデックスを作成してもメリットがないだけでなく、更新速度にも影響します。これは過剰インデックスと呼ばれます。

2. 複合インデックス

たとえば、次のようなステートメントがあります。select * from users where area='beijing' and age=22;

mysql クエリは一度に 1 つのインデックスしか使用できないため、エリアと年齢にそれぞれ単一のインデックスを作成すると、インデックスがない場合に比べてテーブル全体のスキャンの効率、 , 列に複合インデックスを作成すると効率が上がります。(面積、年齢、給与) の複合指数を作成すると、実際には (面積、年齢、給与)、(面積、年齢)、(面積) の 3 つの指数を作成することと同じになり、これを最良左接頭辞特性と呼びます。 。

したがって、複合インデックスを作成するときは、制約として最もよく使用される列を左側に降順で配置する必要があります。

3. インデックスには NULL 値を持つ列は含まれません。

列に NULL 値が含まれている限り、その列はインデックスには含まれません。複合インデックス内の 1 つの列に NULL 値が含まれている限り、この列は複合インデックスに対して無効になります。したがって、データベースを設計するときは、フィールドのデフォルト値を NULL にしないでください。

4. 短いインデックスを使用する

文字列列にインデックスを付けるには、可能であればプレフィックスの長さを指定する必要があります。たとえば、CHAR(255) 列がある場合、ほとんどの値が最初の 10 文字または 20 文字内で一意である場合は、列全体にインデックスを付けないでください。短いインデックスはクエリ速度を向上させるだけでなく、ディスク領域と I/O 操作を節約します。

5. ソートインデックス問題

MySQL クエリはインデックスを 1 つだけ使用するため、where 句でインデックスが使用されている場合、order by のカラムはインデックスを使用しません。したがって、データベースのデフォルトの並べ替えで要件を満たすことができる場合は、並べ替え操作を使用しないでください。複数の列の並べ替えを含めないようにしてください。必要に応じて、これらの列に対して複合インデックスを作成することをお勧めします。

6. Like ステートメントの操作

通常、同様の操作を使用することは推奨されませんが、使用する必要がある場合は、それをどのように使用するかが問題になります。「%aaa%」のようにインデックスは使用されませんが、「aaa%」のようにインデックスが使用されます。

7. 列に対して操作を実行しないでください

select * from users ここで

年(追加)

8. NOT IN 操作は使用しないでください。

NOT IN 操作ではインデックスは使用されず、テーブル全体のスキャンが実行されます。NOT IN は NOT EXISTS に置き換えることができます

おすすめ

転載: blog.csdn.net/qq_40322236/article/details/129674310
おすすめ