Oracle 不一致的查询性能行为

Posted

技术标签:

【中文标题】Oracle 不一致的查询性能行为【英文标题】:Oracle inconsistent performance behaviour of query 【发布时间】:2015-03-06 10:11:57 【问题描述】:

考虑以下查询:

SELECT * 
  FROM (
    SELECT ARRM.*, ROWNUM 
    FROM CRS_ARRANGEMENTS ARRM 
    WHERE 
       CONCAT(ARRM.NBR_ARRANGEMENT, ARRM.TYP_PRODUCT_ARRANGEMENT) > 
       CONCAT('0000000000000000', '0000') 
    ORDER BY 
      ARRM.NBR_ARRANGEMENT, 
      ARRM.TYP_PRODUCT_ARRANGEMENT, 
      ARRM.COD_CURRENCY) 
WHERE ROWNUM < 1000;

此查询在具有 10 000 000 个条目的表上运行。从 Oracle SQL Developer 或我的应用程序运行查询时需要 4 分钟才能运行!不幸的是,这也是我正在编写的应用程序内部的行为。将值从 1000 更改为 10 完全没有影响,这表明它正在执行全表扫描。

但是,当从 SQuirreL 运行时,查询会在 几毫秒内返回。这怎么可能?解释在 SQuirreL 中生成的计划给出:

但是对于同一个查询,Oracle SQL Developer 会生成不同的解释计划:

知道这种行为差异是如何产生的吗?我无法理解它。我尝试使用 JPA 和原始 JDBC。在应用程序中,我需要解析所有 10 000 000 条记录,并且此查询用于分页,因此不能选择等待 4 分钟(这需要 27 天)。

注意:我在 SQuirreL 和我的应用程序中使用相同的 Oracle jdbc 驱动程序,因此这不是问题的根源。

【问题讨论】:

执行 SELECT COUNT(*) .... 看看性能差距是否仍然存在。我猜 SQuirrel 没有得到所有的数据。 SQuirreL 确实获得了所有数据,这没有区别。当数据库表中仅加载 100 000 个条目时,没有这种差异。 你看过这个帖子吗:community.oracle.com/thread/945873 可能是绑定变量偷看的问题。 这不是绑定变量窥视,因为查询对相同的变量执行不同。 【参考方案1】:

显然,国家语言支持或 NLS 参数与它有关。 Oracle SQL Developer 将它们设置为“荷兰语”,这是基于您的区域设置的默认设置,而 SQuirreL 将其设置为 BINARY。这种差异使得优化器使用不同的路径来解决查询。为了在 jdbc 会话中使用正确的 NLS_SORT 参数,需要使用以下命令:

ALTER SESSION SET NLS_SORT=BINARY

那么正确的索引将被用于查询。

【讨论】:

如果使用基于文本的解释计划,这些问题更容易找到。 explain plan for select ... 然后select * from table(dbms_xplan.display); 将在Notes 部分显示差异。出于某种原因,我曾经使用过的每个 IDE 都试图使解释计划“漂亮”,但未能包含关键信息。 我也这样做了@JonHeller,但关于 ns_sort 的信息也不包括在内。花了 12 个小时与 oracle 社区论坛的人一起寻找问题,所以这不是一件简单的事情。

以上是关于Oracle 不一致的查询性能行为的主要内容,如果未能解决你的问题,请参考以下文章

java调oracle 时间不一致

Oracle: 两个SQL语句查询数量不一致。

深入解析:Oracle由11g而始的数据库一致读行为的改变

Oracle Toad SQL 查询导致 id 计数不一致

oracle 查询视图时,count的总数和实际查询出来的总数不一致

雪花使用 ORDER BY 插入不一致的行为