为了便于说明,假设您正在使用一个简单的MySQL"books"表运行一个库,该表有三列:

(身份、头衔、身份)

  • id是主键
  • 这本书的书名是title
  • status可以是描述书籍当前状态的枚举(例如可用、签出、处理、丢失)

一个简单的查询可以报告每个州有多少本书:

SELECT status, COUNT(*) FROM books GROUP BY status

或者具体查找有多少本书:

SELECT COUNT(*) FROM books WHERE status = "AVAILABLE"

然而,一旦表增长到数百万行,这些查询需要几秒钟才能完成.在"状态"栏中添加索引似乎对我的体验没有影响.

除了定期缓存结果或每次书籍更改状态(通过触发器或其他机制)时在单独的表中显式更新摘要信息外,还有什么技术可以加速此类查询?似乎计数查询最终会查看每一行,而且(在不知道更多细节的情况下)我有点惊讶,这些信息无法以某种方式从索引中确定.

UPDATE

使用包含200万行的样本表(带有索引的"status"列),我通过查询对GROUP进行了基准测试.使用InnoDB存储引擎,在我的机器上进行查询需要3.0-3.2秒.使用MyISAM,查询需要0.9-1.1秒.在这两种情况下,计数(*)、计数(状态)或计数(1)之间没有显著差异.

MyISAM确实快了一点,但我很好奇,是否有一种方法可以让一个等价的查询运行快much秒(例如,10-50毫秒——足够快,可以在低流量站点的每个网页请求中调用),而不需要缓存和触发器的精神开销.听起来答案是"没有办法快速运行直接查询",这正是我所期望的——我只是想确保我没有错过一个简单的 Select .

推荐答案

所以问题是

有没有什么技术可以加速这类查询?

其实不是.基于列的存储引擎可能会更快地处理那些SELECT COUNT(*)查询,但对于几乎任何其他查询,它的性能都会更低.

最好的办法是通过触发器维护摘要表.它没有太多开销,而且无论桌子有多大, Select 部分都是即时的.以下是一些样板代码:

DELIMITER //

CREATE TRIGGER ai_books AFTER INSERT ON books
FOR EACH ROW UPDATE books_cnt SET total = total + 1 WHERE status = NEW.status
//
CREATE TRIGGER ad_books AFTER DELETE ON books
FOR EACH ROW UPDATE books_cnt SET total = total - 1 WHERE status = OLD.status;
//
CREATE TRIGGER au_books AFTER UPDATE ON books
FOR EACH ROW
BEGIN
    IF (OLD.status <> NEW.status)
    THEN
        UPDATE books_cnt SET total = total + IF(status = NEW.status, 1, -1) WHERE status IN (OLD.status, NEW.status);
    END IF;
END
//

Mysql相关问答推荐

加载数据本地infile,字段中有双引号和逗号

根据当前表列的值,从SQL中的另一个表中获取数据

基于多行从表中 Select

如何在sql中包含0作为计数?

从单行中获取最大日期的最佳方法

数据导入和默认目标架构空列表. (Mysql 工作台 8)

使用适配器设计模式和外观设计模式实现

mysql insert into select join - 通过连接表将值从一列复制到另一表

MySQL 8.0.30 正则表达式词匹配特殊字符

MYSQL:如何根据之前的相关记录获取记录

在分组结果 MySQL 5.7 版中获取最多的重复值

Mysql 相等性反对 false 或 true

我将如何构建一个 SQL 查询来从交易表中 Select 第一次存款、第二次存款和额外存款

你如何 OR 两个 LIKE 语句?

NodeJS/mySQL - ER_ACCESS_DENIED_ERROR 用户'root'@'localhost'的访问被拒绝(使用密码:是)

如何改进 INSERT INTO ... SELECT 锁定行为

mysql错误'TYPE = MyISAM'

MySQL - 重复表

MySQL CREATE TABLE 语句中的 PRIMARY KEY 定义

AWS RDS 实例升级停机时间