我有一张包含数百万条记录的大桌子。我必须为某个标准做count(*)
,我无法摆脱它。
count()
的 InnoDB
非常昂贵。我一直试图找出MySQL的不同配置,但都是徒劳的。无法加快计算速度。应用程序要求结果小于1秒,因为还有其他依赖查询要运行。
由于InnoDB的计数方式,任何索引都没有帮助。
mysql> EXPLAIN SELECT count(*) FROM `callrequests` WHERE active_call = 1;
+----+-------------+--------------+-------+---------------+-------------+---------+------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+-------+---------------+-------------+---------+------+---------+--------------------------+
| 1 | SIMPLE | callrequests | index | NULL | active_call | 6 | NULL | 5271135 | Using where; Using index |
+----+-------------+--------------+-------+---------------+-------------+---------+------+---------+--------------------------+
mysql> show index from callrequests;
+--------------+------------+------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------+------------+------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| callrequests | 0 | PRIMARY | 1 | id | A | 5271135 | NULL | NULL | | BTREE | | |
| callrequests | 0 | PRIMARY | 2 | campaign_id | A | 5271135 | NULL | NULL | | BTREE | | |
| callrequests | 0 | unique_contact | 1 | campaign_id | A | 4849 | NULL | NULL | | BTREE | | |
| callrequests | 0 | unique_contact | 2 | contact_id | A | 5271135 | NULL | NULL | | BTREE | | |
| callrequests | 0 | unique_contact | 3 | contact | A | 5271135 | NULL | NULL | | BTREE | | |
| callrequests | 1 | fk_callrequest_campaign1_idx | 1 | campaign_id | A | 10 | NULL | NULL | | BTREE | | |
| callrequests | 1 | index4 | 1 | campaign_id | A | 2506 | NULL | NULL | | BTREE | | |
| callrequests | 1 | index4 | 2 | contact | A | 5271135 | NULL | NULL | | BTREE | | |
| callrequests | 1 | phonbook_id_index | 1 | phonebook_id | A | 10 | NULL | NULL | | BTREE | | |
| callrequests | 1 | dnc_group_id_index | 1 | dnc_group_id | A | 2 | NULL | NULL | | BTREE | | |
| callrequests | 1 | active_call | 1 | campaign_id | A | 12 | NULL | NULL | | BTREE | | |
| callrequests | 1 | active_call | 2 | active_call | A | 16 | NULL | NULL | YES | BTREE | | |
| callrequests | 1 | call_status | 1 | call_status | A | 2518 | NULL | NULL | | BTREE | | |
| callrequests | 1 | call_status | 2 | processed | A | 2518 | NULL | NULL | | BTREE | | |
| callrequests | 1 | call_status | 3 | active_call | A | 2518 | NULL | NULL | YES | BTREE | | |
+--------------+------------+------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
服务器是
Xeon machine with 12 CPU cores and 64 GB RAM dedicated 5.6.14-62.0 Percona Server
我的innodb_buffer_pool_size
是38 GB
,所有数据都位于innodb缓冲池中。
答案 0 :(得分:4)
请注意,InnoDB使用WHERE
计数并不比使用MyISAM计算慢。只有一个非常简单的
SELECT COUNT(*) FROM table
使用MyISAM可以更快地计算,因为此数字存储在MyISAMs表元数据中。
如果您的查询包含WHERE
约束,例如:
SELECT COUNT(*) FROM table WHERE active_calls = 1
查询需要访问两个存储引擎中的表数据,MyISAM和InnoDB之间应该没有明显的性能差异。
请查看您的查询未使用任何正确的索引。这不是因为InnoDB"更喜欢"全表扫描,但因为没有合适的索引。
您有一个组合索引(campaign_id, active_calls)
,但active_calls
是索引的第二部分。只要查询中没有使用第一部分,MySQL就无法轻松访问第二部分。
这个简单计数查询的目的是仅在这一列上的另一个索引(active_calls)
。它应该快速运行。
答案 1 :(得分:0)
COUNT(*)-Percona数据库性能博客 https://www.percona.com/blog/2006/12/01/count-for-innodb-tables/
因此,如果您有来自用户的 SELECT COUNT(*)之类的查询,对于 MyISAM 表(MEMORY和其他一些表),faster
将会很多只会从存储的值中读取表中的行数。但是 Innodb 将需要执行full table scan
或full index scan
,因为它没有这样的计数器,对于简单的Innodb表计数器也无法解决,因为不同的事务可能在表格中看到不同的行数。
如果您有类似 SELECT COUNT(*)FROM IMAGE WHERE USER_ID = 5 的查询,则将通过执行index range scan
对MyISAM和Innodb表执行相同的查询。对于MyISAM和Innodb,这可能更快或更慢,具体取决于各种条件。
因此请记住,对于所有COUNT(*)查询而言,Innodb的运行速度并不慢,而对于不带WHERE子句的COUNT(*)查询非常特殊的情况。
答案 2 :(得分:0)
我遇到了类似的问题。我还有一个 int 自动增量主键列。所以我通过这样做解决了这个问题:
select max(id) from table
@mark-khor(其中 id > 0)的建议也对我有用,但我不明白为什么,所以我选择了 max(id)-value...
答案 3 :(得分:-1)
我找到了提高count(*)性能的方法:
SELECT COUNT(*) FROM table WHERE id > 0;