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

Ric*_*ckL 12 sql sql-server oracle optimization

我正在尝试在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)
Run Code Online (Sandbox Code Playgroud)

如果我只运行IN子句中的子部分,它在Oracle中运行得非常快,即

SELECT DISTINCT orderID FROM tasks WHERE
engineer1 IS NOT NULL AND engineer2 IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

为什么整个声明在Oracle中需要这么长时间?在SQL Server中,整个语句运行得很快.

或者,我应该使用更简单/不同/更好的SQL语句吗?

关于这个问题的更多细节:

  • 每个订单都由许多任务组成
  • 每个订单将被分配(其任务中的一个或多个将设置engineer1和engineer2)或订单可以未分配(其所有任务都具有工程师字段的空值)
  • 我试图找到所有未分配的orderID.

如果它有任何区别,表中有大约120k行,每个订单有3个任务,所以~40k不同的订单.

回答答案:

  • 我更喜欢在SQL Server和Oracle中都有效的SQL语句.
  • 任务只有orderID和taskID的索引.
  • 我尝试了该语句的NOT EXISTS版本,但是在我取消它之前它运行了超过3分钟.也许需要一个JOIN版本的声明?
  • 还有一个"订单"表和orderID列.但我试图通过不将其包含在原始SQL语句中来简化问题.

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

执行

ANALYZE TABLE tasks COMPUTE STATISTICS;
Run Code Online (Sandbox Code Playgroud)

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

虽然我仍然很好奇为什么我必须这样做,如果/当我需要再次运行它?

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

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

Oracle还有一个名为"动态采样"的功能,用于对表进行采样,以确定执行时的相关统计信息.它经常用于数据仓库,其中采样的开销远远超过长期运行查询的潜在性能提升.

ham*_*mcn 9

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

ANALYZE TABLE tasks COMPUTE STATISTICS;
Run Code Online (Sandbox Code Playgroud)

  • 这是用于收集统计信息的过时语法.DBMS_STATS是一种更健壮的方式.http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/stats.htm#PFGRF30102 (5认同)
  • 我同意,这已经过时了.请尽量避免使用它.使用DBMS_STATS并确保您也获得索引,您可以在收集表的统计信息时设置cascade => true. (3认同)