【问题标题】:Mysql count performance on very big rows between two dates conditionsMysql 在两个日期条件之间的非常大的行上计算性能
【发布时间】:2021-09-12 13:05:00
【问题描述】:

我在 Innodb 中有一个超过 2000 万行的表。

列是

id, viewable_id, visitor, viewed_at

viewable_idviewed_at 是索引。 当我进行以下查询时

SELECT COUNT(*) 
FROM views_users 
WHERE (viewable_id = 2) 
  and (viewed_at between '2021-04-19 01:38:37' 
  and '2021-06-30 01:38:37');

=> 耗时(3 分 6.72 秒)

解释是

| id | select_type | table       | partitions | type | possible_keys                                             | key                           | key_len | ref   | rows    | filtered | Extra       |
+----+-------------+-------------+------------+------+-----------------------------------------------------------+-------------------------------+---------+-------+---------+----------+-------------+
|  1 | SIMPLE      | views_users | NULL       | ref  | views_users_viewable_id_index,views_users_viewed_at_index | views_users_viewable_id_index | 8       | const | 9554594 |    50.00 | Using where

如何将性能提高到 4 秒以下?

CREATE TABLE views_users (
    id int unsigned NOT NULL AUTO_INCREMENT,
    viewable_type varchar(255) NOT NULL,
    viewable_id bigint unsigned NOT NULL,
    visitor text,
    collection varchar(255) DEFAULT NULL,
    viewed_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    KEY user_id (viewable_id)
) ENGINE=InnoDB AUTO_INCREMENT=20995848
    DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 

【问题讨论】:

  • 请提供SHOW CREATE TABLE views_users
  • @RickJames views_users |创建表 views_users (id int unsigned NOT NULL AUTO_INCREMENT, viewable_type varchar(255) NOT NULL, viewable_id bigint unsigned NOT NULL, visitor text, collection varchar(255) DEFAULT NULL, @98 @timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY user_id (viewable_id) ENGINE=InnoDB AUTO_INCREMENT=20995848 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
  • COUNT(*) 返回什么? innodb_buffer_pool_size 的值是多少?你有多少内存?

标签: mysql sql count query-optimization database-performance


【解决方案1】:

我通过应用MySQL partiotons 将性能提高到不到 2 秒。

我使用viewed_at 列按范围分区。将viewed_at 类型从timestamp 更改为datatime,并使用id 将其作为主键。 让 cronjob 在每个月的第一天运行,将最后一个分区重组为另一个分区,依此类推。

【讨论】:

    【解决方案2】:

    对于这个查询:

    SELECT COUNT(*)
    FROM views_users
    WHERE viewable_id = 2 and
          viewed_at between '2021-04-19 01:38:37' and '2021-06-30 01:38:37';
    

    你可以创建一个索引:

    CREATE INDEX idx_views_users_viewable_id_viewed_at ON views_users(viewable_id, viewed_at);
    

    【讨论】:

    • 不幸的是,我试过这个。需要(2 分 36.57 秒)。
    • @AmrAbdalrahman 。 . .你有指定的索引吗?结果有多大?
    • 是的,views_users_viewable_id_viewed_at 是 50560 views_users_viewable_id_viewed_at 是 4804695
    猜你喜欢
    • 2012-06-14
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 2017-06-13
    • 2015-02-12
    • 1970-01-01
    • 2013-03-30
    • 2012-06-10
    相关资源
    最近更新 更多