下面一个查询需要六十秒 ssinvoice 有30万条记录,ssfeedetail 有400万条记录,想问这样的数据量需要这么多时间正常不。如果要优化,可提达到的理想状态时多少,有什么优化思路。 
select * 
from ssinvoice iv, ssfeedetail f 
where f.ssfd_invoice_no = iv.ssiv_invoice_no 
and f.ssfd_biz_type_code = '3' 
AND f.ssfd_imp_exp_flag = 'E' AND f.ssfd_org_id = '86' 
AND f.ssfd_supplier_code = 'ESHA00001259' 
AND (f.ssfd_payment_flag != 'Y' OR f.ssfd_payment_flag IS NULL) AND (f.ssfd_wo_status = '2' OR f.ssfd_wo_status IS NULL) and iv.ssiv_entrust_no is null Execution Plan 
---------------------------------------------------------- 
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1311 Card=117 Bytes= 
70902) 1 0 NESTED LOOPS (Cost=1311 Card=117 Bytes=70902) 
2 1 TABLE ACCESS (BY GLOBAL INDEX ROWID) OF 'SSFEEDETAIL' (C 
ost=883 Card=214 Bytes=66126) 3 2 INDEX (RANGE SCAN) OF 'IDX_SSFD_ORG_SUPPLIER' (NON-UNI 
QUE) (Cost=29 Card=5986) 4 1 TABLE ACCESS (BY GLOBAL INDEX ROWID) OF 'SSINVOICE' (Cos 
t=2 Card=1 Bytes=297) 5 4 INDEX (UNIQUE SCAN) OF 'PK_SSINVOICE' (UNIQUE) (Cost=1 
Card=1) Statistics 
---------------------------------------------------------- 
71 recursive calls 
0 db block gets 
8131 consistent gets 
5533 physical reads 
0 redo size 
85181 bytes sent via SQL*Net to client 
404 bytes received via SQL*Net from client 
20 SQL*Net roundtrips to/from client 
0 sorts (memory) 
0 sorts (disk) 
285 rows processed 

解决方案 »

  1.   

    对where 语句里面的字段建立索引。这个就不用说了。
    然后我看到你很多判断里面用到了 is null你想办法换个写法,写成 is not null 这样会变得快很多的。为什么我就不知道了。我以前试过,时间相差很多。本来一个需要3秒的,变成is not null 就变成0.几秒了。我是这么写的 (when a is not null then 1 else 2 end)=2这样就能快很多
    还有就是 如果该查询不需要很精确的话,你可以建立物化视图,定在每天晚上进行查询。就可以了。你的查询就查询这个物化视图就可以了
      

  2.   

    思路就是 尽量减少总的数据处理量和 提高单位时间的处理能力你最后的结果只有285条,你的索引可能建得不合理,可以考虑复合索引,另外尝试下更改表的连接顺序 或者采用 hash join
      

  3.   

    select * 这部分需要的字段还是应该列出来。
    如果从某一表中所选出的字段都在这个表的索引中,那么可以减少一步table access by rowid来取得其他不相干的列。
    建立索引的时候除了考虑where部分也要考虑到select子句选择了几个字段。
      

  4.   

    AND f.ssfd_org_id = '86'  
    AND f.ssfd_supplier_code = 'ESHA00001259'  ssfeedetail  上有这两个字段的索引。
      

  5.   

    我觉得关键在两个
    1,select * 估计是你这个慢的最大原因
    2,建议建立索引,并放在专用的分区里
    3,这个也比较关键
    AND (f.ssfd_payment_flag != 'Y' OR f.ssfd_payment_flag IS NULL)  AND (f.ssfd_wo_status = '2' OR f.ssfd_wo_status IS NULL)  这两句有OR的条件应该放在WHERE后的第一和第二项首先判断,这样会加快很多
      

  6.   

    select * 
    from ssinvoice iv, ssfeedetail f 
    where f.ssfd_invoice_no = iv.ssiv_invoice_no 
    and f.ssfd_biz_type_code = '3' 
    AND f.ssfd_imp_exp_flag = 'E' 
    AND f.ssfd_org_id = '86' 
    AND f.ssfd_supplier_code = 'ESHA00001259' 
    AND (f.ssfd_payment_flag != 'Y' OR f.ssfd_payment_flag IS NULL) 
    AND (f.ssfd_wo_status = '2' OR f.ssfd_wo_status IS NULL)  看你的查询语句中对于ssfeedetail表只是和ssinvoice 进行关联,而在下面都是对f表的过滤。
    你看能不能把f先筛出来,然后再与iv关联,这样会快点吧。
    另外,你的表iv与f中的ssfd_invoice_no 与ssiv_invoice_no这两个字段是否建立了索引
      

  7.   

    1.建临时表
    create table t as select * from ssfeedetail f  
    where f.ssfd_biz_type_code = '3'  
    AND f.ssfd_imp_exp_flag = 'E'
    AND f.ssfd_org_id = '86'  
    AND f.ssfd_supplier_code = 'ESHA00001259'  
    AND (f.ssfd_payment_flag != 'Y' OR f.ssfd_payment_flag IS NULL)
    AND (f.ssfd_wo_status = '2' OR f.ssfd_wo_status IS NULL);
    2.查询  
    select *  
    from ssinvoice iv,t f
    where f.ssfd_invoice_no = iv.ssiv_invoice_no  
    and iv.ssiv_entrust_no is null  ;
    分两步试试看会不会快点
      

  8.   

    首先:一条sql语句在oracle中解析的顺序是从右往左进行的也就是离where越远的条件越被更早解析,当然这只是一个方面,所列的查询字段的解析也是从右到左。
    其次:最好不要用*号这样的字符,因为你有几个表,oracle默认将这几个表的所有字段全都列出来,这无疑是一种浪费。
    再者:oracle中百分之90的性能问题都可以用创建索引的方法得以改善,但这又会给系统增加负担,一般提倡记录少的表不要建索引(本人感觉10000条以内),大表必须创建索引,原则是where后最多次数用到的列,或是列的组合,关于索引可以百度,有好多这方面的论述。
    还有:我想强调的是数据的规整问题,真正的表中的数据应该是没有一条是费记录(没有意义的),注意我不光是说一条记录更包括列。
    最后:表间的逻辑关系,如果是存在父子关系那就严格按照父子关系来设计,如果你的表连一个primary key都没有说明建表的人就是不是一个合格的程序员。
      

  9.   

    如果下列几个字段经常在一起作为查询条件的话,可以建立联合索引,比单独建立4个索引效果好不少
    and f.ssfd_biz_type_code = '3' 
    AND f.ssfd_imp_exp_flag = 'E' AND f.ssfd_org_id = '86' 
    AND f.ssfd_supplier_code = 'ESHA00001259'