简体   繁体   中英

Mysql Query run faster

Table structure:

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;

Query:

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

Table holds 110k records out of which 50k type 4 records. Execution time: 0.13 seconds

I know this is fast, but can I make it faster?

I am expecting 1 million records and thus the time would grow quite a bit.

Analyze queries with 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

The "Using temporary; Using filesort" indicates some costly operations. Because the optimizer knows it can't rely on the rows with each value of item being stored together, it needs to scan the whole table and collect the count per distinct item in a temporary table. Then sort the resulting temp table to produce the result.

You need an index on the logs table on columns (type, item) in that order. Then the optimizer knows it can leverage the index tree to scan each value of logs.item fully before moving on to the next value. By doing this, it can skip the temporary table to collect values, and skip the implicit sorting of the result.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM