【发布时间】:2022-01-05 16:19:01
【问题描述】:
问题
我有两个查询,其中一个需要另一个的结果。我的第一个猜测是使用独立的子查询:
SELECT P2.*
FROM ExampleTable P2
WHERE P2.delivery_start >= (
SELECT MIN(P1.delivery_start)
FROM ExampleTable P1
WHERE 1641288602 < P1.delivery_end
);
整个查询需要 5-6 秒,这对我的应用程序来说太长了。一个接一个地运行这些查询只需要大约 800 毫秒:
SELECT MIN(P1.delivery_start)
FROM ExampleTable P1
WHERE 1641288602 < P1.delivery_end;
SELECT P2.*
FROM ExampleTable P2
WHERE P2.delivery_start >= 1641286800;
我正在使用 Mariadb 10.2,并且在 delivery_start 和 delivery_end 上都有索引。
我尝试过的
我使用了 CTE 而不是导致相同性能的子查询。将变量与 SET 一起使用会产生与分别运行两个查询类似的结果,所以我暂时将使用它。
我对所有 3 个查询都运行了 EXPLAIN:
1。用子查询查询
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|---|---|---|---|---|---|---|---|---|---|
| 1 | PRIMARY | P2 | ALL | delivery_start | NULL | NULL | NULL | 6388282 | Using where |
| 2 | SUBQUERY | P1 | range | delivery_end | delivery_end | 4 | NULL | 36378 | Using index condition |
2。单独查询
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | P1 | range | delivery_end | delivery_end | 4 | NULL | 36432 | Using index condition |
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | P2 | range | delivery_start | delivery_start | 4 | NULL | 35944 | Using index condition |
问题
我认为问题出现在第一个EXPLAIN 表中,因为它的类型为ALL,这意味着数据库执行全表扫描。我的问题很简单:为什么?优化器是否无法确定子查询会产生一个我们只需要 range 类型查询的数字吗?为什么它不使用任何索引?
【问题讨论】:
-
子查询的谓词
1641288602 < P1.delivery_end选择了多少行(平均百分比)? -
您在搜索条件中使用了不等式,这会导致大量数据读取。我会假设这是一个非交互式过程,所以 5 秒应该相当不错。现在,如果您想以交互方式处理如此大量的数据,那么您就有了设计问题。
-
@TheImpaler 该表包含大约 600 万个条目,但我认为它不应该相关,因为一个接一个地运行两个查询(即使与
SET变量非交互)运行速度比 5 秒快得多。 -
@BobMcFry 这里存在架构问题。该查询可能适合非交互式使用,但您似乎希望以交互方式使用它。如果是这种情况,您将需要执行预处理(或使用冗余)以大幅减少非活动读取的数量。
-
@TheImpaler 我不想以交互方式使用它。我只想知道为什么性能比我在程序中正确知道的 2 个查询要差得多。
标签: mysql sql mariadb subquery query-optimization