MySQLの:なぜ、使用時間の制限、パフォーマンスに非常に大きな影響を相殺

まず、MySQLのバージョンを説明します。

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.17    |
+-----------+
1 row in set (0.00 sec)

表の構造:

mysql> desc test;
+--------+---------------------+------+-----+---------+----------------+
| Field  | Type                | Null | Key | Default | Extra          |
+--------+---------------------+------+-----+---------+----------------+
| id     | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| val    | int(10) unsigned    | NO   | MUL | 0       |                |
| source | int(10) unsigned    | NO   |     | 0       |                |
+--------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

主キーの増加へのid、valの非ユニークなインデックス。

データの注ぎ大量の500万ドルの合計:

mysql> select count(*) from test;
+----------+
| count(*) |
+----------+
|  5242882 |
+----------+
1 row in set (4.25 sec)

私たちは、オフセット限界が大の行をオフセットする場合、効率があることを知っています:

mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id      | val | source |
+---------+-----+--------+
| 3327622 |   |      4 |
| 3327632 |   |      4 |
| 3327642 |   |      4 |
| 3327652 |   |      4 |
| 3327662 |   |      4 |
+---------+-----+--------+
5 rows in set (15.98 sec)

同じ目的を達成するために、我々は一般的に次の文を書き換えます。

mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id      | val | source | id      |
+---------+-----+--------+---------+
3327622 |   4 |      | 3327622 |
| 3327632 |   |      4 | 3327632 |
3327642 |   4 |      | 3327642 |
| 3327652 |   |      4 | 3327652 |
3327662 |   4 |      | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.38 sec)

時間差は明らかです。

なぜ、上記の結果はありますか?私たちは見てselect * from test where val=4 limit 300000,5;クエリ処理:

  • 索引リーフ・ノード・データへのクエリ。

  • インデックスフィールド値のすべてのクエリは、リーフノードクラスタへのマスターキーに応じて必要。

この図は、次のようになります。

 

最後の5つを取り外し、前に必要、iノード300005回、300005回のクエリデータクラスタ化インデックス、上記のように、最終的な結果は300,000濾過しました。クエリに300000ランダムI / Oデータがセットの結果には表示されませんしながら、MySQLは、データクエリクラスタ化インデックスにランダムI / Oの多くの費用。

きっと誰かが尋ねてきます:インデックスの使用が始まって以来、なぜそのノードに索引リーフ・ノードに沿っていない最初のチェック最後の5つのニーズは、実際のデータを照会するためにクラスタ化インデックスを行きます。唯一の5ランダムI / Oように、プロセスは以下の画像のようになります。

実際に、私はこの質問をお願いしたいと思います。

確認

ここでは、上記の推論を確認するために、実際の動作を見てみましょう。

確認するにはselect * from test where val=4 limit 300000,5、インデックス300 005 300 005クラスタ化インデックスノード上のスキャンデータノードを、我々は、SQL内のノードのインデックスノードを介してMySQLのクエリデータの数をカウントする方法はありません知っている必要があります。私が最初にHandler_read_ *シリーズ、条件を満たすために、残念ながらいない変数を試してみました。

私は唯一の間接的な方法で確認することができます。

プールがバッファのInnoDB。これは、データとインデックス・ページを含む、最近訪問したデータ・ページが含まれています。我々は2つのSQLを実行する必要があるので、バッファー・プール内のデータ・ページの数を比較します。

結果は、実行すると予想されるselect * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;バッファー・プール・データ・ページの数がはるかに少ないよりも後にselect * from test where val=4 limit 300000,5;のみ5回データアクセスページので、以前のSQL対応の数、そしてSQLデータアクセスページ300005回。

select * from test where val=limit 300000,5
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
Empty set (0.04 sec)

可以看出,目前buffer pool中没有关于test表的数据页。

mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id      | val | source |
+---------+-----+--------+
| 3327622 |   |      4 |
| 3327632 |   |      4 |
| 3327642 |   |      4 |
| 3327652 |   |      4 |
| 3327662 |   |      4 |
+---------+-----+--------+
5 rows in set (26.19 sec)

mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY    |     4098 |
| val        |      208 |
+------------+----------+
2 rows in set (0.04 sec)

可以看出,此时buffer pool中关于test表有4098个数据页,208个索引页。

select * from test a inner join (select id from test where val=limit 300000,5) b on a.id=b.id

为了防止上次试验的影响,我们需要清空buffer pool,重启mysql。

mysqladmin shutdown
/usr/local/bin/mysqld_safe &
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
Empty set (0.03 sec)

运行sql:

mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id      | val | source | id      |
+---------+-----+--------+---------+
3327622 |   4 |      | 3327622 |
| 3327632 |   |      4 | 3327632 |
3327642 |   4 |      | 3327642 |
| 3327652 |   |      4 | 3327652 |
3327662 |   4 |      | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.09 sec)

mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY    |        5 |
| val        |      390 |
+------------+----------+
2 rows in set (0.03 sec)

我们可以看明显的看出两者的差别:第一个sql加载了4098个数据页到buffer pool,而第二个sql只加载了5个数据页到buffer pool。符合我们的预测。也证实了为什么第一个sql会慢:读取大量的无用数据行(300000),最后却抛弃掉。

而且这会造成一个问题:加载了很多热点不是很高的数据页到buffer pool,会造成buffer pool的污染,占用buffer pool的空间。

遇到的问题

为了在每次重启时确保清空buffer pool,我们需要关闭innodb_buffer_pool_dump_at_shutdowninnodb_buffer_pool_load_at_startup,这两个选项能够控制数据库关闭时dump出buffer pool中的数据和在数据库开启时载入在磁盘上备份buffer pool的数据。

おすすめ

転載: www.cnblogs.com/ldsweely/p/11987968.html