MySQL のパフォーマンス最適化のアイデアとツール

MySQL のパフォーマンス最適化のアイデアとツール

1. 最適化のアイデア

アーキテクトまたは開発者として、データベースのパフォーマンスの最適化に関してどのように考えていますか?
より具体的に言うと、面接中に次の質問に遭遇した場合、どの次元からデータベースを最適化しますか。どのように答えますか?

パフォーマンスのチューニングについて話すとき、ほとんどの場合、達成したいのはクエリを高速化することです。クエリ アクションは多くのリンクで構成されており、各リンクに時間がかかります。
クエリにかかる時間を短縮したい場合は、すべてのリンクから開始する必要があります。
ここに画像の説明を挿入

2. 接続 - 構成の最適化

最初のリンクは、クライアントがサーバーに接続することです。この接続は、サーバー接続が不十分で、アプリケーションが接続を取得できないことが原因である可能性があります。たとえば、「Mysql: error1040: Too manyconnections」エラーが報告されました。

接続不足の問題は次の 2 つの側面から解決できます。
1. サーバー側から、サーバー側で使用可能な接続の数を増やすことができます。
同時にデータベースにアクセスする複数のアプリケーションまたは多数のリクエストがあり、接続数が十分でない場合は、次のことができます。 (1) 構成パラメータを変更して、使用可能な接続数を増やし、max_connections のサイズを変更します

show variables like 'max_connections'; -- 修改最大连接数,当有多个应用连接的时候

(2) あるいは、非アクティブな接続を適時に解放します。対話型クライアントと非対話型クライアントの両方のデフォルトのタイムアウトは 28800
秒、つまり 8 時間ですが、この値を減らすことができます。

show global variables like 'wait_timeout'; --及时释放不活动的连接,注意不要释放连接池还
在使用的连接

2. クライアント側からは、サーバーから取得するコネクション数を削減できるため、SQL を実行するたびに
新たなコネクションを作成したくない場合は、この時点でコネクションプールを導入することでコネクションの再利用を実現できます。

接続プールの使用レベル
は ORM レベル (MyBatis には接続プールが付属しています)、
または専用の接続プール ツール (Ali's Druid、Spring Boot 2.x バージョンのデフォルトの接続プール Hikari、古い DBCP および C3P0) を使用します。 。

ここでは、データベース構成のレベルからデータベースの最適化について説明しました。データベース自体の構成や
データベース サービスがインストールされているオペレーティング システムの構成に関係なく、構成を最適化する最終的な目標は、CPU、メモリ、ディスク、ネットワークなどのハードウェア自体のパフォーマンスをより有効に活用することです。

ハードウェア環境が異なると、オペレーティング システムの構成と MySQL パラメータも異なり、標準的な構成はありません。

MySQL には、さまざまなスイッチや値の設定を含む多くの設定パラメータがあり、ほとんどのパラメータは、デフォルトのbuffer_pool_size、デフォルトのページ サイズ、InnoDB の同時スレッド数などのデフォルト値を提供します。

これらのデフォルト設定はほとんどの状況のニーズを満たすことができますが、特別なニーズがない限り、パラメータの意味を理解した後で
変更してください。構成を変更する作業は通常、専門の DBA によって行われます。

サーバー側の接続数とクライアント側の接続プールのサイズを合理的に設定することに加えて、キャッシュを導入できます。

3. キャッシュアーキテクチャの最適化

3.1 キャッシュ

アプリケーション システムの同時実行性が非常に大きい場合、キャッシュがないと 2 つの問題が発生します。1 つは
データベースに多大な負荷をもたらすことです。一方、アプリケーションレベルでは、データの動作速度にも影響します。

この問題は、Redis などのサードパーティのキャッシュ サービスを使用して解決できます。
独立したキャッシュ サービスを実行することは、アーキテクチャ レベルでの最適化です。

単一データベース サーバーの読み取りおよび書き込みの負荷を軽減するために、アーキテクチャ レベルで他の最適化措置を講じることもできます。

3.2 マスター/スレーブレプリケーション

単一のデータベース サービスではアクセス要件を満たせない場合は、データベース クラスター ソリューションを実行できます。
クラスタは必然的に問題、つまり異なるノード間のデータの一貫性の問題に直面します。複数のデータベース
ノードが同時に読み書きされる場合、すべてのノードのデータの一貫性を保つにはどうすればよいでしょうか?

このとき、レプリケーション技術(レプリケーション)を利用する必要があり、複製されたノードをマスター、複製されたノードをスレーブと呼びます。

マスター/スレーブ レプリケーションはどのように実装されますか? MySQL アーキテクチャと内部モジュール述べたように、update ステートメントは論理ログである binlog を記録します。

この binlog を使用して、スレーブ サーバーはマスター サーバーの binlog ファイルを取得し、その中の SQL ステートメントを解析して
スレーブ サーバー上で実行して、マスターとスレーブのデータの一貫性を保ちます。

マスターに接続してバイナリ ログを取得し、バイナリ ログを解析してリレー ログに書き込むという 3 つのスレッドが関係しており、このスレッドは I
/O スレッドと呼ばれます。

マスター ノードにはログ ダンプ スレッドがあり、ビンログをスレーブに送信するために使用されます。
スレーブ ライブラリの SQL スレッドは、リレー ログを読み取り、データをデータベースに書き込むために使用されます。

これらは、マスター/スレーブ レプリケーションに関与する 3 つのスレッドです。
ここに画像の説明を挿入

マスター/スレーブ レプリケーション スキームを実装した後は、データをマスター ノードに書き込むだけで、読み取りリクエストをスレーブ ノードに分散できます。このスキームを読み取りと書き込みの分離と呼びます

ここに画像の説明を挿入

読み取りと書き込みを分離すると、データベース サーバーのアクセス圧力をある程度軽減できますが、マスターとスレーブのデータの一貫性には特別な注意を払う必要があります。

マスター/スレーブ レプリケーションを行った後でも、単一のマスター ノードまたは単一のテーブルに格納されているデータが大きすぎる場合 (たとえば、テーブルに数億のデータがある場合)、単一テーブルのクエリ パフォーマンスは依然として低下します
。単一テーブルをさらに改善する必要がある データベース ノードのデータは、サブデータベースとサブテーブルに分割されます。

3.3 サブデータベースとサブテーブル

同時実行圧力を軽減する垂直サブライブラリ。テーブルを水平に分割してストレージのボトルネックを解決します。
データベースの垂直分割の方法では、ビジネスに応じてデータベースを異なるデータベースに分割します。

ここに画像の説明を挿入
ここに画像の説明を挿入

データベースとテーブルを水平分割する方法は、1 つのテーブルのデータを一定の規則に従って複数のデータベースに分散します。

ここに画像の説明を挿入

上記はアーキテクチャレベルでの最適化であり、キャッシュ、マスター/スレーブ、サブデータベース、サブテーブルを使用できます。

3 番目のリンク:
パーサー、語彙および文法分析。主にステートメントの正しさを確認します。ステートメントに間違いがなければ問題はありません。サーバー自体によって処理されます。
ステップ 4: オプティマイザー

4 つのオプティマイザー - SQL ステートメントの分析と最適化

オプティマイザーは SQL ステートメントを分析し、実行計画を生成します。
質問: プロジェクトに取り組んでいるときに、DBA から、
プロジェクトに関する時間のかかるクエリ ステートメントがいくつかリストされた電子メールを受け取ることがあります。それらを最適化しましょう。これらのステートメントはどこから来たのですか?

私たちのサービス層は毎日非常に多くの SQL ステートメントを実行しますが、どの SQL ステートメントが遅いのかをどのようにして知るのでしょうか?
最初のステップでは、SQL の実行を記録する必要があります。

4.1 スロークエリログ スロークエリログ

https://dev.mysql.com/doc/refman/5.7/en/slow-query-log.html

4.1.1 スローログスイッチをオンにする

スロー クエリ ログ (bin ログやオプティマイザー トレースと同じ) をオンにするには料金がかかるため、デフォルトではオフになっています。

show variables like 'slow_query%';

ここに画像の説明を挿入

このスイッチに加えて、SQL の実行時間をスロー ログに記録する時間を制御する別のパラメータがあり、デフォルトは 10 秒です。

showvariableslike'%long_query%';

パラメータは直接動的に変更できます (再起動後は失敗します)。

set @@global.slow_query_log=1;--1开启,0关闭,重启后失效
set @@global.long_query_time=3;--mysql默认的慢查询时间是10秒,另开一个窗口后才会查到最新值
show variables like'%long_query%';
show variables like'%slow_query%';

または、構成ファイル my.cnf を変更します。
次の設定では、スロー クエリ ログのスイッチ、スロー クエリの時間、ログ ファイルの保存パスを定義します。

slow_query_log=ON
long_query_time=2
slow_query_log_file=/var/lib/mysql/localhost-slow.log

遅いクエリをシミュレートします。

select sleep(10);

user_innodb テーブルの 500 万件のデータをクエリします (インデックスがないことを確認します)。

SELECT * FROM `user_innodb` where phone = '136';

4.1.2 スローログ分析

1. ログの内容

show global status like 'slow_queries'; -- 查看有多少慢查询
show variables like '%slow_query%'; -- 获取慢日志目录
cat /var/lib/mysql/ localhost-slow.log

ここに画像の説明を挿入

2. mysqldumpslow
https://dev.mysql.com/doc/refman/5.7/en/mysqldumpslow.html
MySQL は、MySQL の bin ディレクトリにツール mysqldumpslow を提供します。

mysqldumpslow --help

例: クエリ時間が最も長い 10 個の遅い SQL ステートメント:

mysqldumpslow -s t -t 10 -g 'select' /var/lib/mysql/localhost-slow.log

ここに画像の説明を挿入

Count は SQL が実行された回数を表します。Time
は実行時間を表し、かっこは累積
時間を表します。Lock はロック時間を表し、かっこは累積時間を表します。Rows は
返されたレコードの数を表し、かっこはは累積時間です。
スロークエリログに加えて、使用できる SHOW PROFILE ツールもあります。

4.2 プロファイルの表示

https://dev.mysql.com/doc/refman/5.7/en/show-profile.html
SHOW PROFILE は、Google のシニア アーキテクトである Jeremy Cole によって MySQL コミュニティに寄稿されており、
SQL の実行時に使用されるリソースを表示できます。 CPU や IO の消費量などのステートメント。
SQL にヘルプ プロファイルを入力して詳細なヘルプ情報を取得します

4.2.1 有効になっているか確認する

select @@profiling;
set @@profiling=1;

4.2.2 プロファイル統計の表示

(コマンドの最後に s が付いています)

show profiles;

ここに画像の説明を挿入

最後の SQL の実行の詳細を表示して、より時間のかかるリンクを見つけます (s なし)。

show profile;

ここに画像の説明を挿入

6.2E-5 では、小数点を 5 桁左に移動し、0.000062 秒を表します。
ID に基づいて実行の詳細を表示し、続いてクエリ + ID を表示することもできます。

show profile for query 1;

スローログとショープロファイルに加えて、現在のデータベースで実行されている遅いSQLを分析したい場合は、
実行中のスレッドのステータス、サーバーの実行情報、ストレージエンジンの情報を表示して分析することもできます。

4.2.3 その他のシステムコマンド

show processlist 実行スレッド
https://dev.mysql.com/doc/refman/5.7/en/show-processlist.html

show processlist;

これは、ユーザーが実行しているスレッドを表示するための非常に重要なコマンドです。ID 番号に基づいてスレッドを強制終了できます。
テーブルを検索することもできますが、効果は同じです: (順序をグループ化できます)

select * from information_schema.processlist;

ここに画像の説明を挿入

show status サーバーの実行ステータス
説明: https://dev.mysql.com/doc/refman/5.7/en/show-status.html
詳細パラメータ: https://dev.mysql.com/doc/refman/5.7/en /server-status-variables.html
SHOW STATUS は、MySQL サーバーの実行ステータスを表示するために使用されます (再起動後にクリアされます)。セッション スコープとグローバル スコープ
、形式: パラメータ値を使用します。
like をワイルドカードとともに使用してフィルタリングできます。

SHOW GLOBAL STATUS LIKE 'com_select'; -- 查看 select 次数

show Engine ストレージ エンジンの実行情報
https://dev.mysql.com/doc/refman/5.7/en/show-engine.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-standard -monitor.html
表示エンジンは、トランザクションが保持するテーブル ロックおよび行ロック情報、トランザクション ロック待機
ステータス、スレッド セマフォ待機、ファイル IO 要求、バッファ プール統計など、ストレージ エンジンの現在の実行情報を表示するために使用されます。
例えば:

show engine innodb status;

監視情報をエラーログに出力(15秒に1回)する必要がある場合、出力を有効にできます。

show variables like 'innodb_status_output%'; -- 开启输出:
SET GLOBAL innodb_status_output=ON;
SET GLOBAL innodb_status_output_locks=ON;

私たちは現在、サーバーのステータス、ストレージ エンジンのステータス、スレッド実行情報を分析するためのコマンドを非常に多く知っていますが、データベース監視システムを作成するように頼まれたら、どうしますか
?

実際、多くのオープンソースのスロークエリログ監視ツールでは、その原理は実際にシステム変数とステータスを読み取ることです。

どの SQL が遅いのかがわかったので、なぜでしょうか? どこが遅いのでしょうか?

MySQL は実行計画ツールを提供し (アーキテクチャでオプティマイザが最終的に実行計画を生成すると述べました
)、Oracle などの他のデータベースにも同様の機能があります。

EXPLAIN を通じて、SQL クエリ ステートメントを実行するオプティマイザのプロセスをシミュレートし、MySQL が
SQL ステートメントをどのように処理するかを知ることができます。このようにして、ステートメントまたはテーブルのパフォーマンスのボトルネックを分析できます。

MySQL 5.6.3 以前は SELECT のみ解析可能でしたが、MySQL5.6.3 以降は更新、削除、挿入が解析できるようになりました。

4.3 EXPLAIN 実行計画

https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
まず、3 つのテーブルを作成します。クラステーブル 1 つ、教師テーブル 1 つ、教師連絡テーブル 1 つ (インデックスなし)。

DROP TABLE
IF
EXISTS course;
CREATE TABLE `course` ( `cid` INT ( 3 ) DEFAULT NULL, `cname` VARCHAR ( 20 )
DEFAULT NULL, `tid` INT ( 3 ) DEFAULT NULL ) ENGINE = INNODB DEFAULT CHARSET =
utf8mb4;
DROP TABLE
IF
EXISTS teacher;
CREATE TABLE `teacher` ( `tid` INT ( 3 ) DEFAULT NULL, `tname` VARCHAR ( 20 )
DEFAULT NULL, `tcid` INT ( 3 ) DEFAULT NULL ) ENGINE = INNODB DEFAULT CHARSET =
utf8mb4;
DROP TABLE
IF
EXISTS teacher_contact;
CREATE TABLE `teacher_contact` ( `tcid` INT ( 3 ) DEFAULT NULL, `phone` VARCHAR
( 200 ) DEFAULT NULL ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
INSERT INTO `course`
VALUES
( '1', 'mysql', '1' );
INSERT INTO `course`
VALUES
( '2', 'jvm', '1' );
INSERT INTO `course`
VALUES
( '3', 'juc', '2' );
INSERT INTO `course`
VALUES
( '4', 'spring', '3' );
INSERT INTO `teacher`
VALUES
( '1', 'bobo', '1' );
INSERT INTO `teacher`
VALUES
( '2', 'jim', '2' );
INSERT INTO `teacher`
VALUES
( '3', 'dahai', '3' );
INSERT INTO `teacher_contact`
VALUES
( '1', '13688888888' );
INSERT INTO `teacher_contact`
VALUES
( '2', '18166669999' );
INSERT INTO `teacher_contact`
VALUES
( '3', '17722225555' );

Explain の結果には多くのフィールドがあるので、詳しく分析してみましょう。
まず環境を確認します。

select version();
show variables like '%engine%';

4.3.1 ID

id はクエリのシーケンス番号です。

ID 値が異なる場合は、ID 値が大きい方が最初にクエリされます (最初に大きい値、次に小さい値)。

-- 查询 mysql 课程的老师手机号
EXPLAIN SELECT
tc.phone
FROM
teacher_contact tc
WHERE
tcid = ( SELECT tcid FROM teacher t WHERE t.tid = ( SELECT c.tid FROM course
c WHERE c.cname = 'mysql' ) );

クエリ シーケンス: コース c——教師 t——教師_連絡先 tc。
ここに画像の説明を挿入

まず授業スケジュールを確認し、次に教師リストを確認し、最後に教師の連絡先リストを確認します。サブクエリはこの方法でのみ実行でき、
外部クエリは内部結果が取得された後にのみ実行できます。

id値は同じです(上から下まで)

-- 查询课程 ID 为 2,或者联系表 ID 为 3 的老师
EXPLAIN SELECT
t.tname,
c.cname,
tc.phone
FROM
teacher t,
course c,
teacher_contact tc
WHERE
t.tid = c.tid
AND t.tcid = tc.tcid
AND ( c.cid = 2 OR tc.tcid = 3 );

ここに画像の説明を挿入

id値が同じ場合、テーブルクエリシーケンスは上から下へ実行されます。たとえば、このクエリの ID はすべて 1 で、クエリの順序は、
Teacher t (3 エントリ) —— course c (4 エントリ) —— Teacher_contact tc (3 エントリ) です。

同じでも異なる
ID が同じでも異なる場合は、ID が異なる ID は大きい順に小さく、同じ ID を持つ ID は上から下にあることを意味します。

4.3.2 選択タイプのクエリタイプ

すべてがここにリストされているわけではありません (その他: DEPENDENT UNION、DEPENDENT SUBQUERY、MATERIALIZED、UNCACHEABLE SUBQUERY、UNCACHEABLE UNION)。
一般的なクエリ タイプの一部を以下に示します。
SIMPLE
単純クエリ。サブクエリを含まず、関連付けクエリ ユニオンも含まれません。

EXPLAIN SELECT * FROM teacher;

ここに画像の説明を挿入

サブクエリを含む別の例を見てみましょう。

-- 查询 mysql 课程的老师手机号
EXPLAIN SELECT
tc.phone
FROM
teacher_contact tc
WHERE
tcid = ( SELECT tcid FROM teacher t WHERE t.tid = ( SELECT c.tid FROM course
c WHERE c.cname = 'mysql' ) );

ここに画像の説明を挿入

PRIMARY
サブクエリ SQL ステートメントのメインクエリ、つまり最も外側のクエリ。
SUBQUERY
サブクエリ内のすべての内部クエリはSUBQUERY 型です。
DERIVED
派生クエリ。最終的なクエリ結果が取得される前に一時テーブルが使用されることを意味します。例えば:

-- 查询 ID 为 1 或 2 的老师教授的课程
EXPLAIN SELECT
cr.cname
FROM
( SELECT * FROM course WHERE tid = 1 UNION SELECT * FROM course WHERE tid =
2 ) cr;

ここに画像の説明を挿入

関連クエリは右側のテーブル(UNION)を先に実行し、次に左側のテーブルを実行します。タイプは DERIVED
UNION
で、UNION クエリが使用されます。上の例と同じです。
UNION RESULT は
主に、UNION クエリ間にどのテーブルが存在するかを示します。<union2,3> は、id=2 および id=3 のクエリが UNION に存在することを表します。上の例と同じです

4.3.3型接続タイプ

https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-join-types
すべての接続タイプの中で、上のものが最も優れており、下のものがより悪いです。
一般的に使用されるリンク タイプとしては、system > const > eq_ref > ref > range > index >
ここにリストされていないすべて (その他: fulltext、ref_or_null、index_merger、unique_subquery、index_subquery) があります。
上記のアクセス タイプでは、すべてを除いてインデックスを使用できます。

const
プライマリ キー インデックスまたはユニーク インデックスは、1 つのデータの SQL しか検索できません。

DROP TABLE
IF
EXISTS single_data;
CREATE TABLE single_data ( id INT ( 3 ) PRIMARY KEY, content VARCHAR ( 20 ) );
INSERT INTO single_data
VALUES
( 1, 'a' );
EXPLAIN SELECT
*
FROM
single_data a
WHERE
id = 1;

system
system は const の特殊なケースであり、条件を満たすのは 1 行だけです。例: データが 1 つだけ含まれるシステム テーブル。

EXPLAIN SELECT * FROM mysql.proxies_priv;

ここに画像の説明を挿入

eq_ref は
通常、複数のテーブルの結合クエリに表示されます。これは、前のテーブルの各結果について、後のテーブルの結果の 1 行だけが一致できることを意味します。一般に、これは
一意のインデックス クエリ (UNIQUE または PRIMARY KEY) です。
eq_ref は const 以外に最適なアクセス タイプです。

まず、 Teacher テーブル内の冗長なデータを削除します。 Teacher_contact には 3 つのデータがあり、Teacher テーブルには 3 つのデータがあります。

DELETE
FROM
teacher
WHERE
tid IN ( 4, 5, 6 );
COMMIT;
-- 备份
INSERT INTO `teacher`
VALUES
( 4, 'jim', 4 );
INSERT INTO `teacher`
VALUES
( 5, 'bobo', 5 );
INSERT INTO `teacher`
VALUES
( 6, 'seven', 6 );
COMMIT;

Teacher_contact テーブルの tcid (最初のフィールド) の主キー インデックスを作成します。

-- ALTER TABLE teacher_contact DROP PRIMARY KEY;
ALTER TABLE teacher_contact ADD PRIMARY KEY(tcid);

教師テーブルの tcid (3 番目のフィールド) の通常のインデックスを作成します。

-- ALTER TABLE teacher DROP INDEX idx_tcid;
ALTER TABLE teacher ADD INDEX idx_tcid (tcid);

次の SQL ステートメントを実行します。

select t.tcid from teacher t,teacher_contact tc where t.tcid = tc.tcid;

ここに画像の説明を挿入

この時点での実行計画 (Teacher_contact テーブルは eq_ref):
ここに画像の説明を挿入

要約:
上記の 3 つのシステム、const、eq_ref はすべて満たされていますが、求められていないため、基本的にこの状態に最適化するのは困難です。
ref
クエリで一意でないインデックスが使用されているか、関連付け操作でインデックスの左端のプレフィックスのみが使用されます。
例: tcid で通常のインデックス クエリを使用する場合:

explain SELECT * FROM teacher where tcid = 3;

range
インデックス範囲スキャン。
where の後に between and または < または > または >= または <= または in が続く場合、タイプは range です。
インデックスを使用しない場合は、全テーブルスキャン (ALL) にする必要があるため、最初に通常のインデックスを追加します。

-- ALTER TABLE teacher DROP INDEX idx_tid;
ALTER TABLE teacher ADD INDEX idx_tid (tid);

範囲クエリを実行します (フィールドに通常のインデックスを使用):

EXPLAIN SELECT * FROM teacher t WHERE t.tid <3;
-- 或
EXPLAIN SELECT * FROM teacher t WHERE tid BETWEEN 1 AND 2;

ここに画像の説明を挿入

IN クエリも範囲です (フィールドには主キー インデックスがあります)

EXPLAIN SELECT * FROM teacher_contact t WHERE tcid in (1,2,3);

ここに画像の説明を挿入

Index
フル インデックス スキャン。すべてのインデックス内のデータをクエリします (インデックスがない場合よりも高速です)。

EXPLAIN SELECT tid FROM teacher;

ここに画像の説明を挿入

all
フル テーブル スキャン。インデックスがない場合、またはインデックスが使用されていない場合、タイプは ALL です。フルテーブルスキャンを表します。
概要:
一般に、クエリが少なくとも範囲レベルに到達することを確認する必要があり、ref に到達するのが最善です。
ALL (テーブル全体のスキャン) とインデックス (すべてのインデックスのクエリ) の両方を最適化する必要があります。

4.3.4 可能なキー、キー

使用される可能性のあるインデックスと実際に使用されるインデックス。NULL の場合は、インデックスが使用されていないことを意味します。
1 つ以上の possible_key が存在する可能性がありますが、インデックスの使用の可能性は、必ずしもインデックスの使用を意味するわけではありません。
逆に、 possible_key が空の場合、key に値がある可能性はありますか?
テーブルにジョイント インデックスを作成します。

ALTER TABLE user_innodb DROP INDEX comidx_name_phone;
ALTER TABLE user_innodb add INDEX comidx_name_phone (name,phone);

実行計画 (選択名に変更するとインデックスも使用できます):

explain select phone from user_innodb where phone='126';

ここに画像の説明を挿入

結論: 可能です (ここではインデックスをカバーする場合を示します)。
分析の結果、インデックスが使用されていないことが判明した場合は、SQL を確認するか、インデックスを作成します。

4.3.5 key_len

インデックスの長さ (使用されるバイト数)。これは、インデックス フィールドのタイプと長さに関係します。
テーブルにはジョイント インデックスがあります: KEY comidx_name_phone ( name , Phone )

explain select * from user_innodb where name ='jim';

4.3.6行

MySQL は、要求されたデータを返すためにスキャンする行数 (推定) を考慮します。一般に、行数は少ないほど良いです。

4.3.7 フィルタリング済み

このフィールドは、ストレージ エンジンから返されたデータがサーバー層によってフィルタリングされた後に残る、クエリを満たすレコード数の割合をパーセントで示します

4.3.8参照

テーブルからデータをフィルタリングするためにインデックスとともに使用する列または定数。

4.3.9 追加事項

実行計画によって提供される追加情報。
using インデックスは
カバリング インデックスを使用するため、テーブルに戻る必要はありません。

EXPLAIN SELECT tid FROM teacher ;

where
を使用すると、where フィルタリングが使用されます。つまり、ストレージ エンジンから返されたすべてのレコードがクエリ条件を満たしているわけではないため、サーバー層でフィルタリングする必要があります
(インデックスを使用するかどうかとは関係ありません)。

EXPLAIN select * from user_innodb where phone ='13866667777';

ここに画像の説明を挿入

filesort を使用すると
、インデックスを使用して並べ替えることはできず、追加の並べ替えが使用されます (ディスクやファイルとは関係ありません)。最適化が必要です。(複合インデックスの前提条件
)

ALTER TABLE user_innodb DROP INDEX comidx_name_phone;
ALTER TABLE user_innodb add INDEX comidx_name_phone (name,phone);
EXPLAIN select * from user_innodb where name ='jim' order by id;

(IDによる順序が原因)
ここに画像の説明を挿入

usingtemporary は
一時テーブルを使用します。次に例を示します (以下はすべてのケースではありません):
1. インデックスのない個別の列

EXPLAIN select DISTINCT(tid) from teacher t;

2、非インデックス列によるグループ化

EXPLAIN select tname from teacher group by tname;

3.結合を使用する場合、任意の列をグループ化します

EXPLAIN select t.tid from teacher t join course c on t.tid = c.tid group by
t.tid;

複合インデックスの作成などの最適化が必要です。

要約すると、
SQL クエリ ステートメントを実行するオプティマイザのプロセスをシミュレートして、MySQL が SQL ステートメントをどのように処理するかを確認します。このようにして、
ステートメントまたはテーブルのパフォーマンスのボトルネックを分析できます。
問題を分析した後は、SQL ステートメントの具体的な最適化です。

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

SQL ステートメントを最適化する目的は、ほとんどの場合インデックスを使用することです。「mysql インデックスの原則と使用」
では、インデックス作成の原則と、インデックスがどのような状況で使用され、どのような状況でインデックスが使用されないかについても説明します。

5. ストレージエンジン

5.1 ストレージエンジンの選択

異なるビジネス テーブルに対して異なるストレージ エンジンを選択します。たとえば、MyISAM を使用して、多くの操作を含むビジネス テーブルのクエリと挿入を行います。一時データにはメモリを使用します
InnoDB は、通常の同時大規模更新テーブルに使用されます。

5.2 フィールドの定義

原則: データを正しく保存できる最小のデータ型を使用します。
各列に適切なフィールド タイプを選択します。

5.2.1 整数型

TINYINT 1 バイト
SMALLINT 2 バイト
MEDIUMINT 3 バイト
INT、INTEGER 4 バイト
BIGINT 8 バイト

INTは8種類あり、種類ごとに最大記憶範囲が異なります。
性別?ENUM も整数ストレージであるため、TINYINT を使用します。

5.2.2 文字の種類

可変長の場合、varchar はより多くのスペースを節約しますが、varchar フィールドの場合、長さを記録するために 1 バイトが必要です。
固定長には varchar ではなく char を使用してください。

5.2.3 外部キー、トリガー、ビューを使用しないでください

可読性が低下します。
データベースのパフォーマンスに影響します。計算はプログラムに引き渡され、データベースはストレージに集中する必要があります。
データの整合性はプログラム内でチェックする必要があります。

5.2.4 大容量ファイルのストレージ

画像 (base64 エンコーディングなど) や大きなファイルを保存するためにデータベースを使用しないでください。
ファイルを NAS に置き、データベースは URI (相対パス) を保存し、アプリケーションで NAS サーバー アドレスを構成するだけで済みます。

5.2.5 テーブルの分割またはフィールドの冗長性

あまり使用されないフィールドを分割して、列が多すぎたりデータが多すぎたりしないようにします。
たとえば、業務システムでは送受信したすべてのメッセージを記録する必要があり、メッセージを XML 形式で BLOB またはテキストに保存して、重複を追跡および判断し、テーブルを作成してメッセージを保存できます

6 つのまとめ: システムの最適化

ここに画像の説明を挿入

コード、SQL ステートメント、テーブル定義、スキーマ、構成の最適化に加えて、ビジネス レベルでの最適化も無視できません。例を 2 つ挙げてください
:
1) ある年のダブルイレブンに、300 チャージして 50 を獲得するなど、余額宝と残高へのチャージにボーナス アクティビティがあるのはなぜですか?
残高または余額宝を使用して支払いを行うとローカルまたは内部データベースに記録され、銀行カードを使用して支払いを行う場合はインターフェイスを呼び出す必要があり、内部データベースを操作する方が確実に速いためです

2)昨年のダブルイレブンでは、なぜ今日以外の早朝の請求書照会を禁止したのですか?
これは、現在の本業を確保するための格下げ措置です。

3) 近年のダブルイレブンの際、なぜダブルイレブン当日の価格は1週間前からわかるのでしょうか?
販売前の流用。

4) 公安局の同名のクエリは、結果をリアルタイムで返しません (リアルタイム クエリ データベースではありません) が、公式アカウントを通じてプッシュされます。アプリケーション レベルでは、電流制限やMQ ピーク シェービング
の導入など、データベースへの負荷を可能な限り軽減するために最適化するソリューションが他にも多数あります。

なぜ MySQL も使われるのでしょうか? 数千万の同時実行に耐えられる企業もあれば、数百の同時実行に耐えられない企業もあり、
使い方が鍵となります。したがって、データベースの使用が遅いということは、データベース自体が遅いということではなく、場合によっては上位層に最適化する必要があります。

もちろん、リレーショナル データベースで問題を解決できない場合は、検索エンジンやビッグ データ ソリューションを使用する必要があるかもしれませんが、
すべてのデータをリレーショナル データベースに保存する必要があるわけではありません。

おすすめ

転載: blog.csdn.net/lx9876lx/article/details/129134904