Oracle 处理很长的 IN 运算符列表的效率如何

2024-04-01

我有以下查询(这是一个更复杂的查询的简化版本):

SELECT * FROM TPM_TASK
WHERE (PROJECTID, VERSIONID) IN ((3,1), (24,1), (4,1))

在代码中我将构建它(PROJECTID,VERSIONID)以编程方式键列表,并且该列表可能有几千对长。

我的问题是 Oracle 将如何优化这个查询ProjectId and VersionId已编入索引。列表会被转换为哈希表吗,类似于join针对临时表?或者每个键查找一次完成一个?

我在我的测试数据库下尝试了这个查询并得到:

SELECT STATEMENT    68.0    68  2989732 19  8759    68                  ALL_ROWS                                            
   TABLE ACCESS (FULL)  68.0    68  2989732 19  8759    1   TPMDBO  TPM_TASK    FULL    TABLE   ANALYZED    1

但是,我认为该数据库没有足够的数据来保证索引扫描。我尝试对生产进行查询并得到:

SELECT STATEMENT    19.0    19  230367  23  9683    19                  ALL_ROWS                                            
   INLIST ITERATOR                      1                                                               
      TABLE ACCESS (BY INDEX ROWID) 19.0    19  230367  23  9683    1   TPMDBO  TPM_TASK    BY INDEX ROWID  TABLE   ANALYZED    1                                       
         INDEX (RANGE SCAN) 4.0 4   64457   29      1   TPMDBO  TPM_H1_TASK RANGE SCAN  INDEX   ANALYZED                1                           

这似乎达到了索引,但我不确定是什么列表迭代器方法。我猜测这意味着 Oracle 正在迭代列表并对列表中的每个项目进行表访问,这对于数千个键来说可能不会太有效。然而,如果我真的这么做的话,也许 Oracle 足够聪明,能够更好地优化它did给它几千个钥匙。

NOTE:我不想将这些键加载到临时表中,因为坦率地说,我不喜欢临时表在 Oracle 下的工作方式,而且它们通常会导致比其价值更多的挫败感(无论如何,在我的非专家看来)。 )


优化器应根据列表中的项目数和表中的行数做出决定。如果表有数百万行,并且列表甚至有几千个项目,我通常期望它会使用索引进行几千次单行查找。如果表有几千行并且列表有几千个项目,我希望优化器对表进行完整扫描。当然,在中间,所有有趣的事情都会发生,并且很难准确地计算出优化器将选择什么计划。

然而,一般来说,从性能角度来看,动态构建此类查询将会出现问题,不是因为特定查询执行的成本有多高,而是因为您生成的查询不可共享。由于您不能使用绑定变量(或者,如果您使用绑定变量,则需要不同数量的绑定变量)。这迫使 Oracle 每次都对查询进行相当昂贵的硬解析,并对共享池施加压力,这可能会强制排除其他可共享的查询,从而导致系统中进行更多的硬解析。通常,最好将要匹配的数据放入临时表(甚至永久表)中,这样您的查询就可以共享并仅解析一次。

对于 Branko 的评论,虽然 Oracle 的字面量限制为 1000 个,IN列表,仅当您使用“正常”语法时,即

WHERE projectID IN (1,2,3,...,N)

但是,如果您使用之前发布的元组语法,则可以拥有无​​限数量的元素。

因此,举例来说,如果我构建一个包含 2000 个项目的查询,则会收到错误IN list

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_sql_stmt varchar2(32000);
  3    l_cnt      integer;
  4  begin
  5    l_sql_stmt := 'select count(*) from emp where empno in (';
  6    for i in 1..2000
  7    loop
  8      l_sql_stmt := l_sql_stmt || '(1),';
  9    end loop;
 10    l_sql_stmt := rtrim(l_sql_stmt,',') || ')';
 11  --  p.l( l_sql_stmt );
 12    execute immediate l_sql_stmt into l_cnt;
 13* end;
SQL> /
declare
*
ERROR at line 1:
ORA-01795: maximum number of expressions in a list is 1000
ORA-06512: at line 12

但如果我使用元组语法则不会

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_sql_stmt varchar2(32000);
  3    l_cnt      integer;
  4  begin
  5    l_sql_stmt := 'select count(*) from emp where (empno,empno) in (';
  6    for i in 1..2000
  7    loop
  8      l_sql_stmt := l_sql_stmt || '(1,1),';
  9    end loop;
 10    l_sql_stmt := rtrim(l_sql_stmt,',') || ')';
 11  --  p.l( l_sql_stmt );
 12    execute immediate l_sql_stmt into l_cnt;
 13* end;
SQL> /

PL/SQL procedure successfully completed.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Oracle 处理很长的 IN 运算符列表的效率如何 的相关文章

  • SQL Server中的列级与表级约束?

    A 列级 GO CREATE TABLE Products ProductID INT CONSTRAINT pk products pid PRIMARY KEY ProductName VARCHAR 25 GO b 表层 CREATE
  • sql join 告诉我 ID 是否存在于其他表中

    我有 2 张桌子 A B ID FKID 1 3 2 3 3 4 4 4 我需要一个 select 语句 它显示 A 的所有内容 其中一个字段告诉我表 B 是否有任何与该 ID 匹配的 id Desired Result ID hasB 1
  • Sql Server 的夏令时

    我们正在使用一个以 C Unix 格式存储日期的旧应用程序 C 时间基本上是自 1970 年 1 月 1 日以来的秒数 日期以整数形式存储在 SQL Server 数据库中 我正在为使用这些日期的报告编写视图 到目前为止 我正在使用以下命令
  • SQL Server Like 查询不区分大小写

    Query SELECT from Table 2 WHERE name like Joe Output 1 100 Joe 2 200 JOE 3 300 jOE 4 400 joe 为什么不区分大小写 Problem 查询不区分大小写
  • nvarchar 值“3001822585”的转换溢出了 int 列

    我使用以下方法将 Excel 文件导入到 SQL Server Excel 文件将所有值作为字符串 我可以导入文件 除了Barcode SalePrice and Price2 我收到错误 nvarchar 值 3001822585 条形码
  • Magento 设置脚本中的 ALTER TABLE 不使用 SQL

    乔纳森 戴 https stackoverflow com users 336905 jonathan day says 更新不应采用以下形式 SQL命令 我没遇到过 任何 DDL 或 DML 语句不能 通过 Magento 的配置执行 结
  • REGEXP_REPLACE - 仅当包含在 () 中时才从字符串中删除逗号

    我在 oracle 论坛网站找到了一个例子 输入字符串 a b c x y z a xx yy zz x WITH t AS SELECT a b c x y z a xx yy zz x col1 FROM dual SELECT t c
  • RANK() OVER PARTITION 并重置 RANK

    如何获得在分区更改时重新启动的 RANK 我有这张表 ID Date Value 1 2015 01 01 1 2 2015 01 02 1
  • 创建日期范围表

    我正在编写一份需要显示每天值的报告 我有查询的开始日期和结束日期 但我希望避免丢失日期 以防表不包含特定日期的值 我正在考虑创建一个基本日期范围表 其中包含开始和结束之间的所有日期 然后将其与数据表左连接以显示每一天的值 我找到了一些适用于
  • 最近邻居的 Postgis SQL

    我正在尝试计算最近的邻居 为此 我需要传递一个参数来限制与邻居的最大距离 例如 半径1000米内最近的邻居是哪些 我做了以下事情 我用数据创建了表 id name latitude longitude 之后 我执行了以下查询 SELECT
  • 我应该使用平面表还是标准化数据库?

    我目前正在开发一个使用 MySQL 数据库作为后端的 Web 应用程序 在继续下一步之前 我需要知道什么更适合我的情况 简而言之 在这个应用程序中 用户将能够使用任何数字字段 他们决定 构建自己的表单 现在我将其全部存储在通过外键链接的几个
  • SQL UPDATE 语句根据另一个现有行更新列

    基本上我有一个与下表具有相似格式的表格 我想做的是根据这个逻辑更新 Col4 如果 Col2 为空 则用 Col3 更新 Col4 如果 Col2 不为 null 则在 Col1 中查找与 Col2 中的值匹配的值 使用 col3 中的相应
  • 如何计算 Postgres 上图表中所有连接的节点(行)?

    我的桌子有account id and device id One account id可以有多个device ids 反之亦然 我正在尝试计算每个连接的多对多关系的深度 Ex account id device id 1 10 1 11
  • 自动提取数据 - Oracle SQL Developer

    我通过 SQL Developer 连接到 Oracle 数据库 我想编写一个返回每月数据集的查询 然后将该数据提取到分隔文本文件中 我知道如何做到这一点就好了 我想知道是否有一种方法可以编写一个脚本来运行查询并在一年内逐月提取数据 这样我
  • 如何引用下一行的数据?

    我正在 PostgreSQL 9 2 中编写一个函数 对于股票价格和日期的表 我想计算每个条目较前一天的百分比变化 对于最早一天的数据 不会有前一天 因此该条目可以简单地为 Nil 我知道WITH声明可能不应该高于IF陈述 到目前为止 这就
  • ASP SQL Server 连接

  • 如何更新 pl/sql 中嵌套表的列? [复制]

    这个问题在这里已经有答案了 我正在尝试在表中创建一个可以存储多个值的列 如下所示 我有一个学生id std和一个名为marks可以采用几个值 例如2 3 4 我想更新此列表以添加另一个标记2 3 4 5但我不知道怎么做 我如何更新专栏mar
  • 自动删除主键序列中的间隙

    我正在创建一个网页 该网页根据用户操作将数据存储到 MySQL 数据库中 数据库有很多行 行的主键是列 rowID 它只是按顺序对行进行编号 例如 1 2 3 4 用户可以选择删除行 问题是当用户删除最后一行以外的行时 rowID 中有一个
  • 没有为 1 个或多个必需参数给出值。更新SQL

    我正在编写一个程序 当用户在列表视图上选择记录时 该程序会更新密码或积分 我收到错误 没有为 1 个或多个必需参数给出值 我不知道如何纠正 我是否遗漏了一些明显的东西 Dim sql As String UPDATE Users SET P
  • 根据由另一列分组的不同列的最大值获取值[重复]

    这个问题在这里已经有答案了 我想根据由另一列分组的不同列的最大值来获取列的值 我有这张表 KEY NUM VAL A 1 AB B 1 CD B 2 EF C 2 GH C 3 HI D 1 JK D 3 LM 并想要这样的结果 KEY V

随机推荐