mysql 提高InnoDB计数(*)性能

mklgxw1f  于 2023-03-17  发布在  Mysql
关注(0)|答案(5)|浏览(120)

我有一个包含数百万条记录的大表,我必须为某个条件执行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_size38 GB,所有数据都位于innodb缓冲池中。

x33g5p2x

x33g5p2x1#

innodb和myisam在计数方面的差异

请注意,使用WHERE进行计数在InnoDB中并不比在MyISAM中慢。

SELECT COUNT(*) FROM table

使用MyISAM可以更快地计算,因为此数字存储在MyISAM的表元数据中。
例如,如果您有一个带有WHERE约束条件的查询:

SELECT COUNT(*) FROM table WHERE active_calls = 1

查询需要访问两个存储引擎中的表数据,MyISAM和InnoDB之间应该没有显著的性能差异。
关于你的具体问题
请注意,您的查询没有使用任何合适的索引,这并不是因为InnoDB“更喜欢”全表扫描,而是因为不存在合适的索引。
您有一个组合索引(campaign_id, active_calls),但是active_calls是索引的第二部分,只要第一部分没有在查询中使用,MySQL就不容易访问第二部分。
对于这个简单的计数查询,您需要的是仅在这一列上的另一个索引(active_calls),这样它应该运行得很快。

qnyhuwrf

qnyhuwrf2#

我发现了提高count(*)性能的方法:

SELECT COUNT(*) FROM table WHERE id > 0;
b4lqfgs4

b4lqfgs43#

Innodb表的COUNT()- Percona数据库性能博客https://www.percona.com/blog/2006/12/01/count-for-innodb-tables/
因此,如果您有类似**SELECT COUNT的查询(
)来自用户对于 MyISAM 来说,这将是faster(MEMORY和其他一些)表,因为它们只是从存储值中读取表中的行数。但是,Innodb 需要执行full table scanfull index scan,因为它没有这样的计数器,它也不能通过Innodb表的简单计数器来解决,因为不同的事务可能看到表中不同数量的行。
如果您有类似
SELECT COUNT()FROM IMAGE WHERE USER_ID=5**的查询,则通过执行index range scan,将以相同的方式对MyISAM和Innodb表执行此查询。根据不同的条件,对于MyISAM和Innodb,此查询可能会更快或更慢。
因此,请记住Innodb对于所有COUNT(
)查询并不慢,但仅适用于不带WHERE子句的COUNT(*)查询的非常特定的情况。

2ledvvac

2ledvvac4#

我发现COUNT(一个二级索引)的速度很快,但我需要尝试一下,以鼓励mySQL使用PRIMARY索引。
我能够使用PRIMARY索引,并在没有id〉0的情况下获得显著的速度提升:

SELECT COUNT(*) AS count FROM _test_offset WHERE id IS NOT NULL OR id IS NULL;

我还必须以这样一种方式编写查询,即列只被引用一次(用于mysql-rewriter插件),并发现这种类似的查询工作(成本是+10%的时间比上述)

SELECT COUNT(*) AS count FROM _test_offset WHERE CASE WHEN id IS NOT NULL THEN TRUE ELSE TRUE END;

(In mySQL 5.7),它适用于辅助索引、可空/不可空索引和唯一/非唯一索引。在我的简单测试案例中,它显示所需时间减少了27倍。
我会把这个作为Mark Khor's应答器下的一个评论(因为它是高度衍生的),但是没有足够的代表。

nsc4cvqm

nsc4cvqm5#

我也遇到过类似的问题。我也有一个int型自动增量主键列。所以我这样做来解决这个问题:

select max(id) from table

还有@mark-khor(其中id〉0)的建议对我也有用,但我不明白为什么,所以我选择了max(id)-value...

相关问题