mysql - "SELECT COUNT(*)"很慢,即使有 where 子句

标签 mysql performance optimization

我试图弄清楚如何在 MySQL 中优化一个非常慢的查询(我没有设计这个):

SELECT COUNT(*) FROM change_event me WHERE change_event_id > '1212281603783391';
+----------+
| COUNT(*) |
+----------+
|  3224022 |
+----------+
1 row in set (1 min 0.16 sec)

将其与完整计数进行比较:

select count(*) from change_event;
+----------+
| count(*) |
+----------+
|  6069102 |
+----------+
1 row in set (4.21 sec)

解释语句在这里对我没有帮助:

 explain SELECT COUNT(*) FROM change_event me WHERE change_event_id > '1212281603783391'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: me
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 4120213
        Extra: Using where; Using index
1 row in set (0.00 sec)

好的,它仍然认为它需要大约 400 万个条目才能计数,但我可以比这更快地计算文件中的行数!我不明白 MySQL 为什么要花这么长时间。

这是表定义:

CREATE TABLE `change_event` (
  `change_event_id` bigint(20) NOT NULL default '0',
  `timestamp` datetime NOT NULL,
  `change_type` enum('create','update','delete','noop') default NULL,
  `changed_object_type` enum('Brand','Broadcast','Episode','OnDemand') NOT NULL,
  `changed_object_id` varchar(255) default NULL,
  `changed_object_modified` datetime NOT NULL default '1000-01-01 00:00:00',
  `modified` datetime NOT NULL default '1000-01-01 00:00:00',
  `created` datetime NOT NULL default '1000-01-01 00:00:00',
  `pid` char(15) default NULL,
  `episode_pid` char(15) default NULL,
  `import_id` int(11) NOT NULL,
  `status` enum('success','failure') NOT NULL,
  `xml_diff` text,
  `node_digest` char(32) default NULL,
  PRIMARY KEY  (`change_event_id`),
  KEY `idx_change_events_changed_object_id` (`changed_object_id`),
  KEY `idx_change_events_episode_pid` (`episode_pid`),
  KEY `fk_import_id` (`import_id`),
  KEY `idx_change_event_timestamp_ce_id` (`timestamp`,`change_event_id`),
  KEY `idx_change_event_status` (`status`),
  CONSTRAINT `fk_change_event_import` FOREIGN KEY (`import_id`) REFERENCES `import` (`import_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

版本:

$ mysql --version
mysql  Ver 14.12 Distrib 5.0.37, for pc-solaris2.8 (i386) using readline 5.0

我有什么明显的遗漏吗? (是的,我已经尝试过“SELECT COUNT(change_event_id)”,但没有性能差异)。

最佳答案

InnoDB 使用聚集的主键,因此主键与行一起存储在数据页中,而不是在单独的索引页中。为了进行范围扫描,您仍然必须扫描数据页中所有潜在的宽行;请注意,此表包含一个 TEXT 列。

我会尝试两件事:

  1. 运行优化表。这将确保数据页按排序顺序物理存储。可以想象,这可以加快对集群主键的范围扫描。
  2. 仅在 change_event_id 列上创建一个额外的非主索引。这将在索引页中存储该列的副本,这样扫描速度会更快。创建后,检查解释计划以确保它使用新索引。

(如果 change_event_id 列从零开始递增,您可能还希望将其设为 bigint unsigned)

关于mysql - "SELECT COUNT(*)"很慢,即使有 where 子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/511820/

相关文章:

ios - 减少在 iOS 上使用 OpenCv 的方法消耗的内存

php - 用于优化的静态变量

php - 如何使用php中的str_replace函数替换数组中的值

performance - 在 GLSL 中获取纹理有多昂贵?

mysql - 我们可以在插入语句中设置排序规则吗?

c++ - 正弦和余弦哪个更有效? Sin 和 Cos 还是 Sin 和 Sqrt?

c++ - 由于构造函数初始值设定项列表的优化

php - html5 样板中包含“构建”功能

PHP 查询 - 当用户 ID 存储在另一个表中时,如何添加新列并在表中插入用户信息?

mysql - 刷新 InnoDB 缓存