SQL 在使用 ORDER BY

问题描述

我在使用 MysqL ORDER BY 时遇到问题,它会减慢查询速度,我真的不知道为什么,我的查询有点复杂,所以我将其简化为没有连接的轻型查询,但它仍然有效真的很慢。

查询

SELECT
    W.`oid`
FROM
    `z_web_dok` AS W
WHERE
    W.`sent_eRacun` = 1 AND W.`status` IN(8,9) AND W.`Drzava` = 'BiH'
ORDER BY W.`oid` ASC 
LIMIT 0,10

该表有 946,566 行,内存占用 500 MB,我选择的那些字段都索引如下:

oid - INT PRIMARY KEY AUTOINCREMENT
status - INT INDEXED
sent_eRacun - tinyint INDEXED
Drzava - VARCHAR(3) INDEXED

我首先发布解释查询的屏幕截图:

image of explain query

接下来是对数据库执行的查询

executed query to database

这是我删除 ORDER BY 后的速度。

enter image description here

我也尝试过使用 DATETIME 字段进行排序,该字段也有索引,但是我得到的查询与使用主键排序时一样慢,这从今天开始,通常它总是快速而轻便。 什么会导致这样的事情?

解决方法

您在此处使用的查询类型需要复合 covering index。这个应该可以很好地处理您的查询。

CREATE INDEX someName ON z_web_dok (Drzava,sent_eRacun,status,oid);

为什么会这样?您正在寻找前三列的相等匹配,并在第四列上进行排序。查询计划器将使用此索引来满足整个查询。它可以随机访问索引以找到与您的查询匹配的第一行,然后扫描索引以获得所需的行。

专业提示:单列上的索引通常对性能有害,除非它们恰好符合应用程序中特定查询的要求,或者用于主键或外键。您通常选择索引以匹配最活跃或最慢的查询。 编辑 您询问是否最好为应用程序中的每个查询创建特定索引。答案是是。

,

可能有更快的方法。 (或者它可能不会更快。)

IN(8,9) 妨碍了完全有效地轻松处理 WHERE..ORDER BY..LIMIT。可能的解决方案是将其视为 OR,然后转换为 UNION 并使用 LIMIT 做一些技巧,尤其是在您可能还使用 OFFSET 的情况下。

( SELECT ... WHERE .. = 8 AND ... ORDER BY oid LIMIT 10 )
UNION ALL
( SELECT ... WHERE .. = 9 AND ... ORDER BY oid LIMIT 10 )
ORDER BY oid LIMIT 10

这将允许 OJones 描述的覆盖索引在每个子查询中得到充分利用。此外,每个将提供多达 10 行 没有任何临时表或文件排序。然后外部部分将最多排序 20 行并提供“正确”的 10。

对于 OFFSET,请参阅 http://mysql.rjweb.org/doc.php/index_cookbook_mysql#or