How to optimize COUNT(*) performance on InnoDB by using index

前端 未结 4 1873
说谎
说谎 2020-11-28 07:32

I have a largish but narrow InnoDB table with ~9m records. Doing count(*) or count(id) on the table is extremely slow (6+ seconds):



        
相关标签:
4条回答
  • 2020-11-28 07:57

    For the time being I've solved the problem by using this approximation:

    EXPLAIN SELECT COUNT(id) FROM data USE INDEX (PRIMARY)
    

    The approximate number of rows can be read from the rows column of the explain plan when using InnoDB as shown above. When using MyISAM this will remain EMPTY as the table reference isbeing optimized away- so if empty fallback to traditional SELECT COUNT instead.

    0 讨论(0)
  • 2020-11-28 08:02

    As of MySQL 5.1.6 you can use the Event Scheduler and insert the count to a stats table regularly.

    First create a table to hold the count:

    CREATE TABLE stats (
    `key` varchar(50) NOT NULL PRIMARY KEY,
    `value` varchar(100) NOT NULL);
    

    Then create an event to update the table:

    CREATE EVENT update_stats
    ON SCHEDULE
      EVERY 5 MINUTE
    DO
      INSERT INTO stats (`key`, `value`)
      VALUES ('data_count', (select count(id) from data))
      ON DUPLICATE KEY UPDATE value=VALUES(value);
    

    It's not perfect but it offers a self contained solution (no cronjob or queue) that can be easily tailored to run as often as the required freshness of the count.

    0 讨论(0)
  • 2020-11-28 08:04

    Based on @Che code, you can also use triggers on INSERT and on UPDATE to perf2 in order to keep the value in stats table up to date.

    CREATE TRIGGER `count_up` AFTER INSERT ON `perf2` FOR EACH ROW UPDATE `stats`
    SET 
      `stats`.`value` = `stats`.`value` + 1 
    WHERE
      `stats`.`key` = "perf2_count";
    
    CREATE TRIGGER `count_down` AFTER DELETE ON `perf2` FOR EACH ROW UPDATE `stats`
    SET 
      `stats`.`value` = `stats`.`value` - 1 
    WHERE
      `stats`.`key` = "perf2_count";
    

    This would have the advantage of eliminating the performance issue of performing a count(*) and would only be executed when data changes in table perf2

    0 讨论(0)
  • 2020-11-28 08:09

    select max(id) - min(id) from xxx_table where ....

    This will use "Select tables optimized away", and is very fast!!!

    Note max(id) - min(id) is actually bigger than count(1).

    0 讨论(0)
提交回复
热议问题