4

テーブル構造:

CREATE TABLE IF NOT EXISTS `logs` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `user` bigint(20) unsigned NOT NULL,
  `type` tinyint(1) unsigned NOT NULL,
  `date` int(11) unsigned NOT NULL,
  `plus` decimal(10,2) unsigned NOT NULL,
  `minus` decimal(10,2) unsigned NOT NULL,
  `tax` decimal(10,2) unsigned NOT NULL,
  `item` bigint(20) unsigned NOT NULL,
  `info` char(10) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `item` (`item`),
  KEY `user` (`user`),
  KEY `type` (`type`),
  KEY `date` (`date`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 PACK_KEYS=0 ROW_FORMAT=FIXED;

クエリ:

SELECT logs.item, COUNT(logs.item) AS total FROM logs WHERE logs.type = 4 GROUP BY logs.item;

テーブルには110kレコードが保持され、そのうち50kタイプ4レコードが保持されます。実行時間:0.13秒

これが速いことは知っていますが、もっと速くすることはできますか?

私は100万件のレコードを期待しているので、時間はかなり長くなります。

4

1 に答える 1

4

EXPLAINを使用してクエリを分析します。

mysql> EXPLAIN SELECT logs.item, COUNT(logs.item) AS total FROM logs 
    WHERE logs.type = 4 GROUP BY logs.item\G

           id: 1
  select_type: SIMPLE
        table: logs
         type: ref
possible_keys: type
          key: type
      key_len: 1
          ref: const
         rows: 1
        Extra: Using where; Using temporary; Using filesort

「一時的な使用;ファイルソートの使用」は、コストのかかる操作を示しています。オプティマイザは、各値がitem一緒に格納されている行に依存できないことを認識しているため、テーブル全体をスキャンして、一時テーブル内の個別のアイテムごとのカウントを収集する必要があります。次に、結果の一時テーブルを並べ替えて結果を生成します。

ログテーブルの列(タイプ、アイテム)のインデックスがこの順序で必要です。次に、オプティマイザは、インデックスツリーを利用してlogs.itemの各値を完全にスキャンしてから、次の値に進むことができることを認識します。これにより、一時テーブルをスキップして値を収集し、結果の暗黙的な並べ替えをスキップできます。

mysql> CREATE INDEX logs_type_item ON logs (type,item);

mysql> EXPLAIN SELECT logs.item, COUNT(logs.item) AS total FROM logs 
    WHERE logs.type = 4 GROUP BY logs.item\G

           id: 1
  select_type: SIMPLE
        table: logs
         type: ref
possible_keys: type,logs_type_item
          key: logs_type_item
      key_len: 1
          ref: const
         rows: 1
        Extra: Using where
于 2012-12-09T21:15:31.423 に答える