2

900万行を超えるテーブルがあります。インデックスを使用している SELECT クエリがあります。クエリは次のとおりです。

SELECT `username`,`id`
FROM `04c1Tg0M`
WHERE `id` > 9259466
AND `tried` = 0
LIMIT 1;

そのクエリは非常に高速 (0.00 秒) に実行されます。そのクエリの説明は次のとおりです。

+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+
| id | select_type | table    | type  | possible_keys   | key     | key_len | ref  | rows  | Extra       |
+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+
|  1 | SIMPLE      | 04c1Tg0M | range | PRIMARY,triedex | PRIMARY | 4       | NULL | 10822 | Using where |
+----+-------------+----------+-------+-----------------+---------+---------+------+-------+-------------+

ID を 6259466 に変更する以外は、同じクエリを次に示します。

SELECT `username`,`id`
FROM `04c1Tg0M`
WHERE `id` > 5986551
AND `tried` = 0
LIMIT 1;

このクエリが完了するまでに 4.78 秒かかりました。これが問題です。そのクエリの説明は次のとおりです。

+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+
| id | select_type | table    | type | possible_keys   | key     | key_len | ref   | rows    | Extra       |
+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+
|  1 | SIMPLE      | 04c1Tg0M | ref  | PRIMARY,triedex | triedex | 2       | const | 9275107 | Using where |
+----+-------------+----------+------+-----------------+---------+---------+-------+---------+-------------+

ここで何が起こっていますか?どうすれば修正できますか? ここに私のインデックスがあります:

+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table    | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| 04c1Tg0M |          0 | PRIMARY  |            1 | id          | A         |     9275093 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            1 | username    | A         |     9275093 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            2 | id          | A         |     9275093 |     NULL | NULL   |      | BTREE      |         |
| 04c1Tg0M |          1 | pdex     |            3 | tried       | A         |     9275093 |     NULL | NULL   | YES  | BTREE      |         |
| 04c1Tg0M |          1 | triedex  |            1 | tried       | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |
| 04c1Tg0M |          1 | triedex  |            2 | id          | A         |     9275093 |     NULL | NULL   |      | BTREE      |         |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

そして、ここに私のテーブル構造があります:

| 04c1Tg0M | CREATE TABLE `04c1Tg0M` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`tried` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `pdex` (`username`,`id`,`tried`),
KEY `triedex` (`tried`,`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9275108 DEFAULT CHARSET=utf8 |
4

1 に答える 1

1

最初のSQLは10822行を返し、2番目のSQLは9275107行を返します。

とにかく全表スキャンを実行する必要があるため、2番目のクエリで主キー「id」インデックスを使用することはあまり役に立ちません。

MySQLのコストベースのオプティマイザは、2番目のクエリの場合、「試行」のインデックスを使用する方がよいと考えています。

全表スキャンを実行する必要がある場合は、インデックスを使用しない方がよいでしょう。インデックスは追加のディスク読み取りを構成するためです。

クエリで「インデックスの使用」または「インデックスの強制」を使用して、インデックスを使用するかどうかをオプティマイザにヒントを与えることができます。

また、コストベースのオプティマイザが正しく機能するように、テーブルを定期的に分析して統計を更新します。

于 2012-06-19T13:57:23.050 に答える