Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 关于“ORDER BY”和“LIKE”子句的性能调优_Performance_Oracle_Plsql - Fatal编程技术网

Performance 关于“ORDER BY”和“LIKE”子句的性能调优

Performance 关于“ORDER BY”和“LIKE”子句的性能调优,performance,oracle,plsql,Performance,Oracle,Plsql,我有两个表,其中有很多记录,比如TableA和TableB都有大约3000000条记录。vr2_input是用户输入的varchar输入参数,我想获得最多200条最大日期字段的TableA记录,其字符串字段类似于“vr2_input”。这两个表按如下方式连接: select * from( select * from TableA join TableB on TableA.id = TableB.id where TableA.stringFie

我有两个表,其中有很多记录,比如TableA和TableB都有大约3000000条记录。vr2_input是用户输入的varchar输入参数,我想获得最多200条最大日期字段的TableA记录,其字符串字段类似于“vr2_input”。这两个表按如下方式连接:

select * from(   
   select * from 
        TableA join TableB on TableA.id = TableB.id
        where  TableA.stringField like 'vr2_input' || '%'
        order by  TableA.dateField desc   
) where rownum < 201

查询速度很慢,我目不转睛地看了看,发现这是因为like和orderby涉及到完整的表扫描。但是,我找不到解决问题的方法。如何调整这种类型的SQL?我已经在TableA.stringField和TableA.dateField上创建了索引,但是如何在select语句中使用索引功能?数据库是oracle10g。非常感谢


更新:我使用iddqd的建议,只选择我想要的字段并运行解释计划。完成查询大约需要4分钟。IX_TableA_stringField是TableA.srv_ref字段的索引名。我在没有提示的情况下再次运行解释计划,解释计划仍然得到相同的结果

EXPLAIN PLAN FOR
    select * from(
         select   
                 /*+ INDEX(TableB IX_TableA_stringField)*/ 
                  TableA.id,
                    TableA.stringField,
                    TableA.dateField,
                    TableA.someField2,
                   TableA.someField3,
            TableB.someField1,
            TableB.someField2,
            TableB.someField3,
                    from TableA 
                    join TableB  on  TableA.id=TableB.id
                    WHERE TableA.stringField  like '21'||'%'  
                 order by TableA.dateField  desc
        ) where rownum < 201

PLAN_TABLE_OUTPUT                                                                                                                                                                                                                                                                                            
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
Plan hash value: 871807846                                                                                                                                                                                                                                                                    

--------------------------------------------------------------------------------------------------------                                                                                                                                                                           
| Id  | Operation                       | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |                                                                                                                                                                      
--------------------------------------------------------------------------------------------------------                                                                                                                                                                           
|   0 | SELECT STATEMENT                |                      |   200 | 24000 |  3293   (1)| 00:00:18 |                                                                                                                                                                   
|*  1 |  COUNT STOPKEY                  |                      |       |       |            |          |                                                                                                                                                                                   
|   2 |   VIEW                          |                      |  1397 |   163K|  3293   (1)| 00:00:18 |                                                                                                                                                                             
|*  3 |    SORT ORDER BY STOPKEY        |                      |  1397 | 90805 |  3293   (1)| 00:00:18 |                                                                                                                                                              
|   4 |     NESTED LOOPS                |                      |  1397 | 90805 |  3292   (1)| 00:00:18 |                                                                                                                                                                      
|   5 |      TABLE ACCESS BY INDEX ROWID| TableA       |  1397 | 41910 |   492   (1)| 00:00:03 |                                                                                                                                                 
|*  6 |       INDEX RANGE SCAN          | IX_TableA_stringField |  1397 |       |     6   (0)| 00:00:01 |                                                                                                                                                         
|   7 |      TABLE ACCESS BY INDEX ROWID| TableB      |     1 |    35 |     2   (0)| 00:00:01 |                                                                                                                                                      
|*  8 |       INDEX UNIQUE SCAN         | PK_TableB   |     1 |       |     1   (0)| 00:00:01 |                                                                                                                                                            
--------------------------------------------------------------------------------------------------------                                                                                                                                                                           

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

   1 - filter(ROWNUM<201)                                                                                                                                                                                                                                                                      
   3 - filter(ROWNUM<201)                                                                                                                                                                                                                                                                      
   6 - access("TableA"."stringField" LIKE '21%')                                                                                                                                                                                                                                                 
       filter("TableA"."stringField" LIKE '21%')                                                                                                                                                                                                                                                     
   8 - access(TableA"."id"="TableB"."id")       

在stringField和dateField列上创建索引。SQL引擎会自动使用它们。

在stringField和dateField列上创建索引。SQL引擎会自动使用它们。

表A有多少条记录如果是较小的表,您可以在该表上进行选择,然后循环检索表B记录的结果,因为选择和排序都在表A上


一个很好的实验是删除连接并测试其速度。如果允许,还可以将rownum<201作为and子句放在主查询中。很可能此时查询将所有行返回到外部查询,然后对其进行修剪?

如果是较小的表,那么表A有多少条记录?您可以对该表进行选择,然后循环检索表B记录的结果,因为选择和排序都在表A上

select id from(   
   select /*+ INDEX(TableB stringField_indx)*/ TableB.id from 
        TableA join TableB on TableA.id = TableB.id
        where  TableA.stringField like 'vr2_input' || '%'
        order by  TableA.dateField desc   
) where rownum < 201

next:

SELECT * FROM TableB WHERE id iN( id from first query)
一个很好的实验是删除连接并测试其速度。如果允许,还可以将rownum<201作为and子句放在主查询中。很可能此时查询将所有行返回到外部查询,然后对其进行修剪

select id from(   
   select /*+ INDEX(TableB stringField_indx)*/ TableB.id from 
        TableA join TableB on TableA.id = TableB.id
        where  TableA.stringField like 'vr2_input' || '%'
        order by  TableA.dateField desc   
) where rownum < 201

next:

SELECT * FROM TableB WHERE id iN( id from first query)
请发送此表的统计数据和DDL


请发送此表的统计数据和DDL。

如果您有足够的内存,可以提示查询使用哈希连接。如果您有足够的内存,可以提示查询使用哈希联接,请附上解释计划。请附上解释计划

是否需要选择所有列*?如果选择所有列,则优化器更有可能进行完全扫描。如果您需要输出中的所有列,那么最好在内联视图中选择id,然后重新连接以选择其他列,这可以通过索引查找完成。尝试对这两种情况运行解释计划,以查看优化器正在执行的操作。

是否需要选择所有列*?如果选择所有列,则优化器更有可能进行完全扫描。如果您需要输出中的所有列,那么最好在内联视图中选择id,然后重新连接以选择其他列,这可以通过索引查找完成。尝试对这两种情况运行解释计划,看看优化器在做什么。

您说运行查询大约需要4分钟。解释计划输出显示估计为18秒。因此,在这种情况下,优化器的某些估计可能远远不够。它仍然可以选择最好的计划,但可能不是

在这种情况下,第一步是获得实际的执行计划和统计数据。使用提示/*+gather\u plan\u statistics*/运行查询,然后立即从tabledbms\u xplan执行select*命令。显示\u cursornull、null和'ALLSTATS LAST'

这将显示运行的实际执行计划,并且对于每个步骤,它将显示估计行、实际行和实际花费的时间。在这里发布输出,也许我们可以对您的问题说一些更有意义的话

如果没有这些信息,我的建议是尝试以下对查询的重写。我认为这是等效的,因为ID似乎是TableB的主键

select TableA.id,
       TableA.stringField,
       TableA.dateField,
       TableA.someField2,
       TableA.someField3,
       TableB.someField1,
       TableB.someField2,
       TableB.someField3,
  from (select * from(
         select   
                  TableA.id,
                    TableA.stringField,
                    TableA.dateField,
                    TableA.someField2,
                    TableA.someField3,
                    from TableA 
                    WHERE TableA.stringField  like '21'||'%'  
                 order by TableA.dateField  desc
          )
          where rownum < 201
       ) TableA
       join TableB  on  TableA.id=TableB.id

您说运行查询大约需要4分钟。解释计划输出显示估计为18秒。因此,在这种情况下,优化器的某些估计可能远远不够。它仍然可以选择最好的计划,但可能不是

在这种情况下,第一步是获得实际的执行计划和统计数据。使用提示/*+gather\u plan\u statistics*/运行查询,然后立即从tabledbms\u xplan执行select*命令。显示\u cursornull、null和'ALLSTATS LAST'

这将显示运行的实际执行计划,并且对于每个步骤,它将显示估计行、实际行和实际花费的时间。把结果贴在这里,也许我们可以说点什么 你对你的问题很有意义

如果没有这些信息,我的建议是尝试以下对查询的重写。我认为这是等效的,因为ID似乎是TableB的主键

select TableA.id,
       TableA.stringField,
       TableA.dateField,
       TableA.someField2,
       TableA.someField3,
       TableB.someField1,
       TableB.someField2,
       TableB.someField3,
  from (select * from(
         select   
                  TableA.id,
                    TableA.stringField,
                    TableA.dateField,
                    TableA.someField2,
                    TableA.someField3,
                    from TableA 
                    WHERE TableA.stringField  like '21'||'%'  
                 order by TableA.dateField  desc
          )
          where rownum < 201
       ) TableA
       join TableB  on  TableA.id=TableB.id

您可以在表A上创建一个函数索引。根据是否满足“vr2_输入”| |“%”之类的TableA.stringField条件返回1或0。该索引将使查询运行得更快。函数的逻辑将是

if (substr(TableA.stringField, 1, 9) = 'vr2_input'
THEN 
    return 1;
else 
    return 0;

使用实际列名而不是*可能会有所帮助。至少应删除常用列名

您可以在表A上创建一个函数索引。根据是否满足“vr2_输入”| |“%”之类的TableA.stringField条件返回1或0。该索引将使查询运行得更快。函数的逻辑将是

if (substr(TableA.stringField, 1, 9) = 'vr2_input'
THEN 
    return 1;
else 
    return 0;

使用实际列名而不是*可能会有所帮助。至少应删除常用列名

要优化like谓词,可以创建上下文索引并使用contains子句

看:


要优化like谓词,可以创建上下文索引并使用contains子句

看:


谢谢

我已经在TableA.stringField和TableA.dateField上创建了一个索引,但速度非常慢。最好在执行了诸如create table、alter table或create index之类的ddl语句后收集新的统计数据。我已经在TableA.stringField和TableA.dateField上创建了一个索引,但它非常慢。最好在执行ddl语句(如create table、alter table或create index)后收集新的统计数据。您说它很慢-有多慢:秒、分钟、,小时数?Oracle不会对包含LIKE或ORDER BY的查询使用索引,这不是真的。您可以在SQL Plus中使用AUTOTRACE ON运行它并发布信息吗?如果没有提示,您从EXPLAIN PLAN中会得到什么?对我来说,提示是最后的手段,而不是第一件要尝试的事情。我在没有提示的情况下再次运行解释计划,解释计划仍然得到相同的结果。因此,我想知道所使用的提示是否有用。你说它很慢-有多慢:秒、分钟、小时?Oracle不会使用索引进行包含LIKE或ORDER BY的查询,这不是真的。你能在SQL Plus中使用AUTOTRACE ON运行它并发布信息吗?如果没有提示,你会从EXPLAIN PLAN中得到什么?对我来说,提示是最后的手段,而不是第一件要尝试的事情。我在没有提示的情况下再次运行解释计划,解释计划仍然得到相同的结果。所以我想知道使用的提示是否有用+1,收集计划统计数据是如此的酷。我不敢相信我以前从未听说过它。+1,收集计划统计数据太酷了。真不敢相信我以前没听说过。