我正在尝试在 Oracle 中运行以下 SQL 语句,它需要很长时间才能运行:
SELECT orderID FROM tasks WHERE orderID NOT IN
(SELECT DISTINCT orderID FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL)
如果我只运行 IN 子句中的子部分,它在 Oracle 中运行得非常快,即
SELECT DISTINCT orderID FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL
为什么整个语句在 Oracle 中需要这么长时间?在 SQL Server 中,整个语句运行得很快。
或者,我应该使用更简单/不同/更好的 SQL 语句吗?
有关该问题的更多详细信息:
- 每个订单由许多任务组成
- 将分配每个订单(其中一个或多个任务将设置engineer1 和engineer2)或者可以取消分配订单(其所有任务的engineer 字段都具有空值)
- 我正在尝试查找所有未分配的 orderID。
以防万一,表中有大约 120k 行,每个订单有 3 个任务,因此大约有 40k 个不同的订单。
对答案的回应:
- 我更喜欢在 SQL Server 和 Oracle 中都可以使用的 SQL 语句。
- 任务仅在 orderID 和 taskID 上有一个索引。
- 我尝试了语句的 NOT EXISTS 版本,但在我取消它之前它运行了 3 多分钟。也许需要一个 JOIN 版本的语句?
- 还有一个带有 orderID 列的“订单”表。但我试图通过不将其包含在原始 SQL 语句中来简化问题。
我猜在原始 SQL 语句中,子查询每次都会为 SQL 语句第一部分中的每一行运行 - 即使它是静态的并且只需要运行一次?
执行
ANALYZE TABLE tasks COMPUTE STATISTICS;
使我原来的 SQL 语句执行得更快。
尽管我仍然很好奇为什么我必须这样做,以及是否/何时需要再次运行它?
统计信息为 Oracle 的基于成本的优化器提供了确定不同执行计划效率所需的信息:例如,表中的行数、行的平均宽度、每列的最高和最低值、每列不同值的数量,索引的聚类因子等。
在一个小型数据库中,您可以设置一个工作来每天晚上收集统计数据,然后不用管它。其实这是10g下的默认值。对于较大的实现,您通常必须权衡执行计划的稳定性与数据变化的方式,这是一个棘手的平衡。
Oracle 还有一个称为“动态采样”的功能,用于对表进行采样以确定执行时的相关统计信息。它更常用于数据仓库,其中采样的开销超过了长时间运行查询的潜在性能提升。