MySQLのパフォーマンス[クエリインターセプト分析]

クエリの最適化

小さなテーブルが大きなテーブルを動かす

最適化の原則:小さなテーブルは大きなテーブルを駆動し、即小的数据集驱动大的数据集。

select * from A where id in (select id from B)
等价于:
for select id from B
for select * from A where A.id = B.id

テーブルBのデータセットをテーブルAのデータセットよりも小さくする必要がある場合、inは存在するよりも優れています。

select * from A where exists (select 1 from B where B.id = A.id)
等价于:
for select * from A
for select * from B where B.id = A.id

AテーブルのデータセットがBテーブルのデータセットよりも小さい場合、existsが優先されます。

  • 存在する

存在するテーブルから選択(サブクエリ)

この文法は次のように理解できます。条件付き検証のためにメインクエリのデータをサブクエリに入れ、メインクエリのデータ結果が検証結果(trueまたはfalse)に従って保持されるかどうかを決定します。

キーワード最適化による注文者

  • 単語順に並べ替え、インデックスを使用して並べ替え、filesortを使用して並べ替えを回避

MySQLは2つのソート方法をサポートしています。FileSortとインデックス、インデックスは非常に効率的です。つまり、MySQLはインデックス自体をスキャンしてソートを完了します。FileSortメソッドは効率が低下します。

並べ替えは2つの条件を満たし、インデックスを使用して並べ替えます

Order byステートメントは
インデックスの左端の列を使用します。Where 句とOrder By句の条件付き列の組み合わせは、インデックスの左端の列と一致します。

  • インデックス列のソート操作をできる限り完了し、インデックスの左端の最適な接頭辞の原則に従います。
  • インデックス列にない場合、filesortには2つのアルゴリズムがあります。mysqlは、双方向のソートと一方向のソートを開始する必要があります。
  1. 双方向ソート

    • MySQL 4.1以前は、双方向のソートが使用されていました。これは、文字どおりディスクを2回スキャンしてデータを取得し、行ポインターと列順を読み取ってソートし、ソートされたリストをスキャンして、リストの値に従って書き直すことを意味していました。リストから対応するデータ出力を読み取ります。
    • ディスクからソートフィールドをフェッチし、バッファでソートしてから、ディスクから他のフィールドをフェッチします。
  2. データのバッチをフェッチするには、ディスクを2回スキャンする必要があります。ご存じのとおり、I \ Oは非常に時間がかかるため、mysql4.1の後に、2番目に改善されたアルゴリズム(一方向ソート)が登場しました。

  3. 片道ソート

    • クエリに必要なすべての列をディスクから読み取り、列内の順序に従ってバッファ内で並べ替えてから、並べ替えられたリストをスキャンして出力します。高速であり、データの2回目の読み取りを回避できます。また、ランダムIOをシーケンシャルIOに変換しますが、各行をメモリに保存するため、より多くのスペースを使用します。
  • 最適化戦略

sort_buffer_sizeパラメータの設定を増やし
ますmax_length_for_sort_dataパラメータの設定を増やします

ここに画像の説明を挿入

キーワード最適化によるグループ化

group byの本質は、インデックスによって構築された最良の左プレフィックスに従って、ソートしてからグループ化することです。

インデックス列を使用できない場合は、max_length_for_sort_dataパラメータの設定を増やし、sort_buffer_sizeパラメータの設定を増やします。

whereがhaveよりも高い場合、whereに記述できる条件はhaveによって制限されません。

クエリログが遅い

MySQLのスロークエリログは、MySQLによって提供されるログレコードです。これは、対応する時間がMySQLのしきい値を超えるステートメントを記録するために使用されます。具体的には、実行時間がSQLに相当するlong_query_timeを超える場合、スロークエリログに記録されます。

具体的には、実行時間がSQLに相当するlong_query_timeを超えると、スロークエリログに記録されます。long_query_timeのデフォルト値は10です。これは、ステートメントが10秒以上実行されることを意味します。

これは、どのSQLが最大耐久時間の値を超えているかを確認するために使用されます。たとえば、SQLが5秒を超えて実行された場合、それが遅いSQLであっても、5秒を超えるSQLを収集し、Explainを使用して包括的な分析を実行したいと考えています。

スロークエリログの使用方法

デフォルトでは、MySQLデータベースはスロークエリログを有効にしません。このパラメーターを手動で設定する必要があります。
もちろん、チューニングに必要ない場合は、このパラメーターを有効にすることはお勧めしません。スロークエリログをオンにすると、ある程度のパフォーマンスへの影響が生じるためです。スロークエリログは、ファイルへのログレコードの書き込みをサポートしています。

オンになっているかどうか、オンにする方法を確認する

デフォルト:show variables like '%slow_query_log%';
オン:set global slow_query_log = 1;

永続的に有効にする方法は、構成ファイルmy.cnfを変更するだけです(長時間開くことはお勧めしません)。

my.cnfファイルを変更し、[mysqld]のパラメーター
slow_query_logおよびslow_query_log_fileを追加または変更してから、MySQLサーバーを再起動します。

特定の構成パラメーターは次のとおりです。

slow_query_log=1
slow_query_log_file=/var/lib/mysql/mysql-slow.log

スロークエリのパラメーターslow_query_log_fileについては、スロークエリログファイルのストレージパスを指定し、システムはデフォルトでデフォルトファイルhost_name-slow.logを指定します(パラメーターslow_query_log_fileが指定されていない場合)

スロークエリログにはどのようなSQLが記録されますか?

これは、パラメータlong_query_timeによって制御されます。デフォルトでは、long_query_timeの値は10秒です。
コマンド:show variables like 'long_query_time%';

ここに画像の説明を挿入

コマンドを使用するか、my.cnfパラメータで変更できます。
実行時間がlong_query_timeと完全に等しい場合、それは記録されません。つまり、mysqlソースコードにあります判断大于 long_query_time,而非大于等于

事例

  1. 現在満杯の秒数を確認してください> show variables like 'long_query_time%';
  2. 遅いしきい値時間を設定します。set global long_query_time=3;

ここに画像の説明を挿入

  1. 設定後に変更が表示されないのはなぜですか

変更された値を確認するには、再接続するか、新しいセッションを開く必要があります。
show variables like 'long_query_time%;
show global variables like 'long_query_time';

ここに画像の説明を挿入

  1. 遅いSQLとフォローアップ分析を記録する

ここに画像の説明を挿入

  1. 現在のシステムにある低速のクエリレコードの数をクエリする

show global status like '%Slow_queries%%';

ここに画像の説明を挿入

遅いログオンを永続的に設定する

【mysqld】下配置:
slow_query_log==1;
slow_query_log_file=/var/lib/mysql/atguigu-slow.log
long_query_time=3;
log_output=FILE

ログ分析ツールmysqldumpslow

本番環境で、ログを手動で分析し、SQLを見つけて分析する場合、MySQLはログ分析ツールmysqldumpslowを提供しています。

mysqldumpslow:のヘルプコマンドを確認します。mysqldumpslow --help各パラメータの意味は次のとおりです。

  1. s:ソート方法を示します
  2. c:訪問数
  3. I:ロックタイム
  4. r:レコードを返す
  5. t:クエリ時間
  6. aI:平均ロック時間
  7. ar:返されたレコードの平均数
  8. at:平均クエリ時間
  9. t:返されるデータの数
  10. g:大文字と小文字を区別しない通常の一致パターンに一致します。

一般的な例:

// 得到返回记录集最多的 10 个SQL
mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log

// 得到访问次数最多的 10 个SQL
mysqldumpslow -s c -t 10 /var/lib/mysql/atguigu-slow.log

// 得到按照时间排序的前 10 条里面含有左连接的查询语句
mysqldumpslow -s t -t -g "left join" /var/lib/mysql/atguigu-slow.log

// 另外建立在使用这些命令时结合 | 和 more 使用,否则有可能出现爆屏情况
mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log | more

バッチデータスクリプト

たとえば、テーブルに1000Wのデータを挿入します。

1.テーブルを作成する

# 新建库
create database bigData;
use bigData;

# 建部门表 dept
create table dept(
id int unsigned primary key auto_increment,
deptno mediumint unsigned not null default 0,
dname varchar(20) not null default "",
loc varchar(13) not null default ""
)engine=innodb default charset=GBK;

# 建员工表 emp
create table emp(
id int unsigned primary key auto_increment,
empno mediumint unsigned not null default 0,/*编号*/
ename varchar(20) not null default "",/*名字*/
job varchar(9) not null default "",/*工作*/
mgr mediumint unsigned not null default 0,/*上级编号*/
hiredate date not null,/*入职时间*/
sal decimal(7,2) not null,/*薪水*/
comm decimal(7,2) not null,/*红利*/
deptno mediumint unsigned not null default 0/*部门编号*/
)engine=innodb default charset=gbk;

2.パラメータlog_bin_trust_function_creatorsを設定します

エラーが報告された場合、関数を作成します。この関数には決定論的なものはありません...

# 由于开启过慢查询日志,因为我们开启了 bin-log,我们就必须为我们的 function 指定一个参数。
show variables like 'log_bin_trust_function_creators';
set global log_bin_trust_function_creators=1;

# 这样添加了参数以后,如果 mysqld 重启,上述参数又会消失,永久方法:
windows:my.ini文件[mysqld]加上log_bin_trust_function_creators=1
linux:/etc/my.cnf下my.cnf文件[mysqld]加上log_bin_trust_function_creators=1

3.各データが異なることを確認する関数を作成します

  • 文字列をランダムに生成します。
DELIMITER $$ 
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) 
BEGIN 
	DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'; 
	DECLARE return_str VARCHAR(255) DEFAULT ''; 
	DECLARE i INT DEFAULT 0; 
	WHILE i < n DO 
	SET return_str=CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1)); 
	SET i = i + 1; 
	END WHILE; 
	RETURN return_str; 
END $$

# 假如要删除此函数
# drop function rand_string;
  • 部門番号をランダムに生成します。
DELIMITER $$ 
CREATE FUNCTION rand_num()
RETURNS INT(5)
BEGIN 
	DECLARE i INT DEFAULT 0;
	SET i = FLOOR(100+RAND()*10);
	RETURN i;
END $$

# 假如要删除此函数
# drop function rand_num;

4.ストアドプロシージャを作成する

  • empテーブルにデータを挿入するストアドプロシージャを作成する
# 执行存储过程,往 emp 表中添加随机数据
DELIMITER $$
CREATE PROCEDURE insert_emp(IN START INT(10), IN max_num INT(10))
BEGIN
	DECLARE i INT DEFAULT 0;
	# set autocommit = 0 把 autocommit 设置为0
	SET autocommit=0;
	REPEAT
	SET i = i + 1;
	INSERT INTO emp (empno, ename, job, mgr, hiredate, sal, comm, deptno) VALUES ((START+i), rand_string(6),'SALESMAN',0001,CURDATE(),2000,400,rand_num());
	UNTIL i = max_num
	END REPEAT;
	COMMIT;
END $$
  • ストアドプロシージャを作成してデータをdeptテーブルに挿入する
// 执行存储过程,往 dept 表中添加随机数据
DELIMITER $$
CREATE PROCEDURE insert_dept(IN START INT(10), IN max_num INT(10))
BEGIN
	DECLARE i INT DEFAULT 0;
	SET autocommit = 0;
	REPEAT
	SET i = i + 1;
	INSERT INTO dept (deptno, dname, loc) VALUES ((START+i), rand_string(10), rand_string(8));
	UNTIL i = max_num
	END REPEAT;
	COMMIT;
END $$

5.ストアドプロシージャを呼び出す

  • 最初に部署に電話
DELIMITER ;
CALL insert_dept(100,10);
  • empを呼び出すとき[マシンのパフォーマンスが良くない場合は、挿入数を適切に減らすことができます]
DELIMITER ;
CALL insert_emp(100001,500000);

ここに画像の説明を挿入

プロフィールを表示

プロファイルの表示は、現在のセッションでのステートメント実行のリソース消費を分析するために使用できるmysqlによって提供されます。SQLチューニング測定に使用できます

公式ウェブサイト:http : //dev.mysql.com/doc/refman/5.5/en/show-profile.html

デフォルトでは、パラメーターは閉じており、最後の15回の実行結果が保存されます

プロファイル分析ステップを表示

  1. サポートしていますか?現在のバージョンがサポートしているかどうかを確認します
Show variables like 'profiling';

ここに画像の説明を挿入

  1. オープン機能、デフォルトはクローズ、使用前に開く必要があります
set profiling=on;
  1. SQLを実行する
  2. 結果を見る:show profiles;
  3. 診断SQL:show profile cpu,block io for query 上一步前面的问题 SQL 数字号码;

パラメーターの備考:
タイプ:
| ALL-すべてのオーバーヘッド情報を表示
| BLOCK
IO- ブロックIO関連のオーバーヘッドを表示| CONTEXT SWITCHES --context switch関連のオーバーヘッド
| CPU --CPU 関連のオーバーヘッド情報を表示
| IPC- 送受信の表示関連コスト情報
|
MEMORY- メモリ関連コスト情報の表示| PAGE FAULTS-ページフォールト関連コスト情報の表示
| SOURCE-Source_function、Source_file、Source_lineに関連するコスト情報の表示
| SWAPS-交換時間に関連するコストの表示

  1. 日常の開発で注意が必要な結論

converting HEAP to MyISAM 查询结果太大,内存都不够用了往磁盘上搬了。

Creating tmp table 创建临时表:拷贝数据到临时表;用完再删除。

Copying to tmp table on disk 把内存中临时表复制到磁盘,危险!!!

locked

グローバルクエリログ

本番環境ではこの機能を有効にしないでください。

構成開始

在 mysql 的 my.cnf 中,配置如下:
# 开启
general_log=1
# 记录日志文件的路径
general_log_file=/path/logfile
# 输出格式
log_output=FILE

コードスタート

set global general_log=1;
set global log_output='TABLE';
// 此命令用于查看你编写的 sql 语句
select * from mysql.general_log;

本番環境ではこの機能を有効にしないでください。

おすすめ

転載: blog.csdn.net/qq_43647359/article/details/105822697
おすすめ