1

MySQLのドキュメントによると、左端のフィールドが基準の一部である場合でも、複合インデックスが使用されます。ただし、このテーブルは主キーと正しく結合しません。左の2つのフィールドの別のインデックスを追加する必要があり、それを使用します。

テーブルの1つはメモリです。デフォルトでは、メモリはグループ/順序に使用できないハッシュインデックスを使用します。ただし、インデックスではなくメモリテーブルのすべての行を使用しているので、それが問題に関係しているとは思いません。

私は何が欠けていますか?

mysql> show create table pr_temp;
| pr_temp | CREATE TEMPORARY TABLE `pr_temp` (
`player_id` int(10) unsigned NOT NULL,
`insert_date` date NOT NULL,
[...]
PRIMARY KEY (`player_id`,`insert_date`) USING BTREE,
KEY `insert_date` (`insert_date`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8  |

mysql> show create table player_game_record;
| player_tank_record | CREATE TABLE `player_game_record` (
`player_id` int(10) unsigned NOT NULL,
`game_id` smallint(5) unsigned NOT NULL,
`insert_date` date NOT NULL,
[...]
PRIMARY KEY (`player_id`,`insert_date`,`game_id`),
KEY `insert_date` (`insert_date`),
KEY `player_date` (`player_id`,`insert_date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 DATA DIRECTORY='...' INDEX DIRECTORY='...' |

mysql> explain select pgr.* from player_game_record pgr inner join pr_temp on   pgr.player_id = pr_temp.player_id and pgr.insert_date = pr_temp.date_prev;                      
+----+-------------+---------+------+---------------------------------+-------------+---------+-------------------------------------------------------------------------+--------+-------+
| id | select_type | table   | type | possible_keys                   | key         | key_len | ref                                                                     | rows       | Extra |
+----+-------------+---------+------+---------------------------------+-------------+---------+-------------------------------------------------------------------------+--------+-------+
|  1 | SIMPLE      | pr_temp | ALL  | PRIMARY                         | NULL        | NULL    | NULL                                                                    | 174683   |       |
|  1 | SIMPLE      | pgr     | ref  | PRIMARY,insert_date,player_date | player_date | 7       | test_gamedb.pr_temp.player_id,test_gamedb.pr_temp.date_prev |     21 |       |
+----+-------------+---------+------+---------------------------------+-------------+---------+-------------------------------------------------------------------------+--------+-------+
2 rows in set (0.00 sec)

mysql> explain select pgr.* from player_game_record pgr force index (primary) inner join pr_temp on pgr.player_id = pr_temp.player_id and pgr.insert_date = pr_temp.date_prev;
+----+-------------+---------+------+---------------+---------+---------+-------------------------------------------------------------------------+---------+-------+
| id | select_type | table   | type | possible_keys | key     | key_len | ref                                                                       | rows    | Extra |
+----+-------------+---------+------+---------------+---------+---------+-------------------------------------------------------------------------+---------+-------+
|  1 | SIMPLE      | pr_temp | ALL  | PRIMARY       | NULL    | NULL    | NULL                                                                    |  174683 |       |
|  1 | SIMPLE      | pgr     | ref  | PRIMARY       | PRIMARY | 7       | test_gamedb.pr_temp.player_id,test_gamedb.pr_temp.date_prev | 2873031 |       |
+----+-------------+---------+------+---------------+---------+---------+-------------------------------------------------------------------------+---------+-------+
2 rows in set (0.00 sec)

左の2つの列(player_id、insert_date)を使用して、主キーが機能するはずです。ただし、デフォルトではplayer_dateインデックスが使用され、プライマリインデックスを使用するように強制すると、両方ではなく1つのフィールドのみを使用しているように見えます。

Update2:Mysqlバージョン5.5.27-ログUpdate3 :(これは他のテストを試しているときにplayer_dateインデックスを削除した後です)

mysql> show indexes in player_game_record;
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table              | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| player_game_record |          0 | PRIMARY     |            1 | player_id   | A            |        NULL |     NULL | NULL   |      | BTREE      |         |               |
| player_game_record |          0 | PRIMARY     |            2 | insert_date | A         |        NULL |     NULL | NULL   |      | BTREE      |         |               |
| player_game_record |          0 | PRIMARY     |            3 | game_id     | A         |   576276246 |     NULL | NULL   |      | BTREE      |         |               |
| player_game_record |          1 | insert_date |            1 | insert_date | A         |       33304 |     NULL | NULL   |      | BTREE      |         |               |
+--------------------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (1.08 sec)


mysql> select count(*) from player_game_record;
+-----------+
| count(*)  |
+-----------+
| 576276246 |
+-----------+
1 row in set (0.00 sec)
4

1 に答える 1

1

MEMORYもう一方のテーブルについて話しているので、一方のテーブルでのストレージエンジンの使用は、ここではまったく問題にならないことに同意します。

また、インデックスの左端のプレフィックスは、使用しようとしている方法とまったく同じように使用できることに同意します。また、主キーを他のインデックスとまったく同じように使用できなかった理由は考えられません。

これは頭​​を悩ませてきました。作成した新しいインデックスは、主キーの左側と同じである必要があります。それでは、なぜ同じように動作しないのでしょうか。私には2つの考えがあり、InnoDBの場合ほどMyISAMの内部に精通していなくても、どちらも同じ推奨事項につながります。(余談ですが、MyISAMよりもInnoDBをお勧めします。)

データの挿入を開始したとき、主キーのインデックスはおそらくテーブル上にありましたが、データのほとんどまたはすべてがすでに存在している間に新しいインデックスが追加されました。これは、新しいインデックスが内部的に適切に整理されていることを示していますが、主キーインデックスは、データの読み込み時に作成されているため、非常に断片化されている可能性があります。

オプティマイザが表示する行数は、インデックス統計に基づいています。これは、挿入順序が原因で主キーで不正確になる可能性があります。

断片化理論は、インデックスとして主キーを使用したクエリがそれほど高速ではない理由を説明している可能性があります。インデックス統計理論は、オプティマイザーがそのような異なる行数考え出す理由を説明し、オプティマイザーがそのインデックスを使用する代わりに全表スキャンを選択した理由を説明する場合があります(これは推測にすぎません。利用可能な説明)。

これらの2つの考えに基づいて私が提案することはOPTIMIZE TABLE、あなたのテーブルで実行されています。その新しいインデックスを作成するのに12時間かかった場合、テーブルの最適化にはそれ以上の時間がかかる可能性があります。

おそらく役立つ:http ://www.dbasquare.com/2012/07/09/data-fragmentation-problem-in-mysql-myisam/

于 2013-01-20T07:54:27.653 に答える