一尘不染

优化在Oracle上运行缓慢,在SQL Server上快速运行的SELECT查询

sql

我正在尝试在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。

以防万一它有所不同,表中约有12万行,每个订单有3个任务,因此约有40k个不同的订单。

对答案的回应:

  • 我希望可以在SQL Server和Oracle中都可以使用的SQL语句。
  • 任务仅在orderID和taskID上具有索引。
  • 我尝试了该语句的NOT EXISTS版本,但在取消它之前运行了3分钟以上。可能需要该语句的JOIN版本?
  • 还有一个带有“ orderID”列的“ orders”表。但是我试图通过不将其包含在原始SQL语句中来简化该问题。

我猜想在原始SQL语句中,子查询每次都针对SQL语句第一部分中的每一行运行-即使它是静态的,应该只需要运行一次?

执行中

ANALYZE TABLE tasks COMPUTE STATISTICS;

使我原来的SQL语句执行得更快。

尽管我仍然很好奇为什么必须这样做,以及是否/何时需要再次运行它?

统计信息提供了Oracle基于成本的优化器信息,该信息是确定不同执行计划的效率所必需的:例如,表中的行数,行的平均宽度,每列的最高和最低值,每列的不同值的数量,索引的聚类因子等。

在小型数据库中,您可以设置一个工作来每晚收集统计信息,而不必理会它。实际上,这是10g以下的默认设置。对于较大的实现,通常必须权衡执行计划的稳定性和数据更改的方式,这是一个棘手的平衡。

Oracle还具有称为“动态采样”的功能,该功能用于对表进行采样以确定执行时的相关统计信息。它更常用于数据仓库,因为对于长时间运行的查询而言,其采样开销超过了潜在的性能提升。


阅读 111

收藏
2021-03-17

共1个答案

一尘不染

如果您分析所涉及的表,这种类型的问题通常会消失(因此,Oracle对数据的分布有了更好的了解)

ANALYZE TABLE tasks COMPUTE STATISTICS;
2021-03-17