-3

我正在处理一个需要优化查询的维护项目。这是非常复杂的查询,所以我分为 5 个部分。

在一个表“文档”中有字段

document_id(PK)
doc_name
fk_product_id
issue_date
date_expiring
status

查询是

SELECT SQL_CALC_FOUND_ROWS this.* , COUNT(this.document_id) as count_document_id,
FROM ( SELECT * from documents where status != 'D' order by date_expiring desc ) this 

有数百万条记录,但以上查询仅返回记录。我不明白这个查询是什么意思/它将返回什么记录。

4

1 回答 1

1

让我们分解一下。

子查询开始:

SELECT * FROM documents WHERE status != 'D' ORDER BY date_expiring desc

结果集是documents表的子集。

接下来,主要查询的FROM

FROM ( /* that subquery up there ^^^ */ ) this

这将子查询的结果集视为虚拟表this为其命名。MySQL 的查询优化器通常足够聪明,可以避免这种子查询模式的额外开销。

接下来,我们将看看SELECT

SELECT SQL_CALC_FOUND_ROWS 
       this.* , 
       COUNT(this.document_id) as count_document_id
 FROM ...

SQL_CALC_FOUND_ROWS在这里已弃用且毫无意义,但它没有害处。它已被弃用,因为有更好的方法来计算行数。这是没有意义的,因为这个查询必须只返回一行;继续阅读。

COUNT(this.document_id) as count_document_id计算来自包含非 NULL document_id 的子查询的所有行。但是document_id是基础表的主键,所以它永远不会为空。因此COUNT(*)也可以正常工作。而且,顺便说一句,它使子查询的ORDER BY子句完全没有意义。

因为 SELECT 行上有一个聚合函数并且没有 GROUP BY 子句,所以该查询聚合了子查询中的所有行并只产生一行。

this.*在标准 SQL 中是完全错误的。它在 MySQL 中毫无意义:您从该查询返回的单行包含计数:这很好。但是通过指定this.*,您还可以从子查询中仅获取一个随机选择的行的内容。当您迁移到 MySQL 8.0 时,这将中断。MySQL 对 GROUP BY 有一个臭名昭著的非标准扩展,可以实现这种随机的事情。

我希望这有帮助。接管某人的代码会很有趣,对吧?

于 2020-09-18T11:13:01.423 回答