【问题标题】:Alter session slows down the query through HibernateAlter session 通过 Hibernate 减慢查询速度
【发布时间】:2017-02-24 08:25:26
【问题描述】:

我正在使用 Oracle 11gR2 和 Hibernate 4.2.1。 我的应用程序是搜索应用程序。

只有 SELECT 操作,都是原生查询。

Oracle 默认使用区分大小写的排序。 我想将其覆盖为不区分大小写。

我在这里看到了几个选项http://docs.oracle.com/cd/A81042_01/DOC/server.816/a76966/ch2.htm#91066

现在我在执行任何搜索之前使用此查询。

ALTER SESSION SET NLS_SORT='BINARY_CI'

如果我在执行搜索查询之前执行上述 sql,则休眠大约需要 15 分钟才能从搜索查询返回。 如果我在 Sql Developer 中执行此操作,它会在几秒钟内返回。

为什么会有这种两种不同的行为, 我该怎么做才能摆脱这种缓慢?

注意:我总是为每次搜索打开一个新的 Hibernate 会话。

这是我的 sql:

SELECT *
FROM (SELECT
        row_.*,
        rownum rownum_
      FROM (SELECT
               a, b, c, d, e,
               RTRIM(XMLAGG(XMLELEMENT("x", f || ', ') ORDER BY f ASC)
                     .extract('//text()').getClobVal(), ', ') AS f,
               RTRIM(
                  XMLAGG(XMLELEMENT("x", g || ', ') ORDER BY g ASC)
                  .extract('//text()').getClobVal(), ', ')    AS g
             FROM ( SELECT src.a, src.b, src.c, src.d, src.e, src.f, src.g
                      FROM src src
                     WHERE upper(pp) = 'PP'
                       AND upper(qq) = 'QQ'
                       AND upper(rr) = 'RR'
                       AND upper(ss) = 'SS'
                       AND upper(tt) = 'TT')
             GROUP BY a, b, c, d, e
             ORDER BY b ASC) row_
      WHERE rownum <= 400
) WHERE rownum_ > 0;

LIKE 操作自带这么多字段,是动态sql查询。如果我使用order by upper(B) asc Sql Developer 也需要同样的时间。 但按结果排序与NLS_SORT=BINARY_CI 相同。我使用了UPPER('B') 索引,但没有什么对我有用。

A 的长度 = 10-15 个字符

B 的长度 = 34-50 个字符

C 的长度 = 5-10 个字符

A、B 和 C 是可通过 app 排序的字段。 这个 SRC 表有 300 万多条记录。 我们最终得到了一个 SRC 表,它是一个物化视图。

SQL 的业务逻辑完全没问题。 所有的排序表字段和其他字段都被 UPPER 索引。

【问题讨论】:

  • 您是说ALTER SESSION 只会对通过休眠的查询产生负面影响吗? ALTER 可以很容易地阻止索引访问路径,使查询显着变慢。但它应该在 SQL Developer 中以相同的方式工作。您确定两个环境都在运行完全相同的 SQL 语句吗?
  • @jonearles 是的,我运行了相同的查询。但是通过休眠它不是一个单一的SQL。我必须使用同一个会话执行 2 个查询。在 Sql developer 上,我打开一个选项卡,运行 ALTER 查询,然后在同一选项卡中运行 SELECT *...ORDER BY 查询。工作正常。那里没有缓慢。有时这可能不是我想的 Hibernate 问题。但这正在发生:(
  • 您能否发布通过 hibernate 和 SQL Developer 对数据库运行的确切 SQL 语句?解决方案可能是创建具有特定排序的基于函数的索引,但我们需要查看查询才能确定。
  • 我将发布 sql。我使用了UPPER() 索引。

标签: sql oracle hibernate query-performance


【解决方案1】:

UPPER() 和 BINARY_CI 可能产生相同的结果,但 Oracle 不能互换使用它们。要使用索引和 BINARY_CI,您必须像这样创建索引:

create index src_nlssort_index on src(nlssort(b, 'nls_sort=''BINARY_CI'''));

样本表和混合大小写数据

create table src(b varchar2(100) not null);
insert into src select 'MiXeD CAse '||level from dual connect by level <= 100000;

默认情况下upper()谓词可以对upper()索引进行范围扫描

create index src_upper_index on src(upper(b));

explain plan for
select * from src where upper(b) = 'MIXED CASE 1';

select * from table(dbms_xplan.display(format => '-rows -bytes -cost -predicate 
    -note'));

Plan hash value: 1533361696

------------------------------------------------------------------
| Id  | Operation                   | Name            | Time     |
------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                 | 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| SRC             | 00:00:01 |
|   2 |   INDEX RANGE SCAN          | SRC_UPPER_INDEX | 00:00:01 |
------------------------------------------------------------------

BINARY_CI 和 LINGUISTIC 不会使用索引

alter session set nls_sort='binary_ci';
alter session set nls_comp='linguistic';

explain plan for
select * from src where b = 'MIXED CASE 1';

select * from table(dbms_xplan.display(format => '-rows -bytes -cost -note'));

Plan hash value: 3368256651

---------------------------------------------
| Id  | Operation         | Name | Time     |
---------------------------------------------
|   0 | SELECT STATEMENT  |      | 00:00:02 |
|*  1 |  TABLE ACCESS FULL| SRC  | 00:00:02 |
---------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(NLSSORT("B",'nls_sort=''BINARY_CI''')=HEXTORAW('6D69786564
              2063617365203100') )

基于函数的 NLSSORT() 索引启用索引范围扫描

create index src_nlssort_index on src(nlssort(b, 'nls_sort=''BINARY_CI'''));

explain plan for
select * from src where b = 'MIXED CASE 1';

select * from table(dbms_xplan.display(format => '-rows -bytes -cost -note'));

Plan hash value: 478278159

--------------------------------------------------------------------
| Id  | Operation                   | Name              | Time     |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                   | 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| SRC               | 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | SRC_NLSSORT_INDEX | 00:00:01 |
--------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(NLSSORT("B",'nls_sort=''BINARY_CI''')=HEXTORAW('6D69786564
              2063617365203100') )

【讨论】:

  • 仍然在发生。最后,我添加了 3 个额外的列 UPPER_A、UPPER_B、UPPER_C 作为临时解决方案。现在我只做ORDER BY UPPER_B。这可能不是一个好的解决方案。但现在我同意这个。我尝试了所有我能想到的组合,而不考虑它们的目的。没有一个有效。
  • 这种情况只发生在少数搜索场景中。我们在 UAT 阶段发现了这一点。所有其他人甚至可以使用ORDER BY UPPER。如果我使用任何索引或将 ORDER BY UPPER 放入最内部的 SELECT 中,它就可以工作。但这不是我想做的。 Aggregation-SELECT 查询不喜欢这些索引,ORDER BY UPPER 或 Altering NLS_SORT SOMETIMES 仅适用于某些场景。
【解决方案2】:

我调查并发现参数 NLS_COMP y NLS_SORT 可能会影响 oracle 如何使用字符串的执行计划(在比较或排序时)。

不需要更改 NLS 会话。添加

ORDER BY NLSSORT(column , 'NLS_SORT=BINARY_CI') 

为 NLS 添加索引就足够了

create index column_index_binary as NLSSORT(column , 'NLS_SORT=BINARY_CI')

我在这个问题中找到了一个问题的线索,所以我正在偿还。

Why oracle stored procedure execution time is greatly increased depending on how it is executed?

【讨论】:

    猜你喜欢
    • 2011-10-04
    • 2015-11-27
    • 2017-12-24
    • 1970-01-01
    • 2016-08-28
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 2019-11-22
    相关资源
    最近更新 更多