NBh*_*tti 1 mysql performance innodb count
我有一张大桌子,上百万条记录。我必须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 | | |
+--------------+------------+------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
Run Code Online (Sandbox Code Playgroud)
服务器是
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缓冲池中。
我找到了提高 count(*) 性能的方法:
SELECT COUNT(*) FROM table WHERE id > 0;
Run Code Online (Sandbox Code Playgroud)
请注意,WHERE使用InnoDB进行计数并不比使用MyISAM慢。只是很裸
SELECT COUNT(*) FROM table
Run Code Online (Sandbox Code Playgroud)
可以使用MyISAM更快地计算出该数字,因为该数字存储在MyISAMs表元数据中。
例如,如果您有WHERE约束查询:
SELECT COUNT(*) FROM table WHERE active_calls = 1
Run Code Online (Sandbox Code Playgroud)
该查询需要访问两个存储引擎中的表数据,并且MyISAM和InnoDB之间应该没有明显的性能差异。
请确保您的查询未使用任何适当的索引。这不是因为InnoDB“喜欢”全表扫描,而是因为不存在适当的索引。
您有一个组合索引(campaign_id, active_calls),但它active_calls是索引的第二部分。只要查询中未使用第一部分,MySQL都不容易访问第二部分。
对于此简单计数查询,您想要的是(active_calls)仅在该列上的另一个索引。然后它应该运行得很快。
Innodb 表的 COUNT(*) - Percona 数据库性能博客\n https://www.percona.com/blog/2006/12/01/count-for-innodb-tables/
\n\n因此,如果您有像SELECT COUNT(*) FROM USERfaster这样的查询,这对于MyISAM (MEMORY 和其他一些)表来说会很重要,因为它们只是从存储的值中读取表中的行数。然而, Innodb需要执行full table scan,或者full index scan因为它没有这样的计数器,它也可以通过 Innodb 表的简单单计数器来解决,因为不同的事务可能会看到表中不同的行数。
如果您有像SELECT COUNT(*) FROM IMAGE WHERE USER_ID=5这样的查询,则对于 MyISAM 和 Innodb 表,此查询将以相同的方式执行index range scan。对于 MyISAM 和 Innodb,这可能更快或更慢,具体取决于各种条件。
因此请记住,Innodb 对于 ALL COUNT(*) 查询并不慢,但仅对于不带 WHERE 子句的 COUNT(*) 查询的非常特定情况而言慢。
\n