繁体   English   中英

优化巨型表上的选择查询?

[英]Optimize select query on huge tables?

我试图在给定索引列值的Oracle数据库中抓取特定行。 我选择索引列后跟整个行数据以便于处理。 桌子上大约有1.5亿行,我选择大约100到20万行。 我正在使用NVL()替换IN子句中的空值,因为我在JAVA中动态创建这些语句。 IN子句被分成由OR组合在一起的1000个索引块,以避免“列表中的最大表达式数为1000”错误。

您可以想象,此查询需要很长时间才能运行。 有什么我可以做的来优化这个查询,但保持相同的功能? (忽略索引值,因为它们只是一个例子)

select INDEX_COLUMN_A, INDEX_COLUMN_B, INDEX_COLUMN_C, TABLE.* from TABLE     
Where (NVL(INDEX_COLUMN_A,''), NVL(INDEX_COLUMN_B,''), NVL(INDEX_COLUMN_C,'')) 
IN (('1','1','1'), ('2','2','2'), ... ('1000','1000','1000')) 
OR (NVL(INDEX_COLUMN_A,''), NVL(INDEX_COLUMN_B,''), NVL(INDEX_COLUMN_C,'')) 
IN (('1001','1001','1001'), ('1002','1002','1002'), ... ('2000','2000','2000')) 
OR...

如果在('1','1','1')('2000','2000','2000')等测试值中不可能遇到null ,则可以安全地避免nvl()处于条件状态:

select 
  INDEX_COLUMN_A, INDEX_COLUMN_B, INDEX_COLUMN_C, 
  TABLE.* 
from 
  TABLE     
where 
  (INDEX_COLUMN_A, INDEX_COLUMN_B, INDEX_COLUMN_C) 
  in (
    ('1','1','1'), 
    ('2','2','2'), 
    ...,
    ('1000','1000','1000')
  ) 
  OR 
  (INDEX_COLUMN_A, INDEX_COLUMN_B, INDEX_COLUMN_C) 
  in (
    ('1001','1001','1001'), 
    ('1002','1002','1002'),
     ...,
    ('2000','2000','2000')
  ) 
  or
  ...

此外,表达式如a in (x1,x2) or a in (x3,x4)表示((a=x1 or a=x2) or (a=x3 or a=x4)) :在这种情况下托架可以没有后果被省略(a=x1 or a=x2 or a=x3 or a=x4)可与被缩短in表达为a in (x1, x2, x3, x4) 因此,初始查询(如果要测试的值中没有空值)与以下内容相同:

select 
  INDEX_COLUMN_A, INDEX_COLUMN_B, INDEX_COLUMN_C, 
  TABLE.* 
from 
  TABLE     
where 
  (INDEX_COLUMN_A, INDEX_COLUMN_B, INDEX_COLUMN_C) 
  in (
    ('1','1','1'), 
    ('2','2','2'), 
    ...,
    ('1000','1000','1000')
    ...,
    ('1001','1001','1001'), 
    ('1002','1002','1002'),
     ...,
    ('2000','2000','2000')
  ) 

PS

a in (x,y,z)只是由or ((a=x) or (a=y or (a=z))连接的等式关系集的快捷方式,而null永远不等于null ,因此表达式为null in (x,y,z)永远不会返回true无论xyz值如何。所以如果你真的需要处理null值,那么表达式必须改为nvl(a,'some_never_encountered_value') in (nvl('1', 'some_never_encountered_value'), nvl('2','some_never_encountered_value'),...) 。但是在这种情况下你不能在表上使用简单索引。可以构建功能索引来处理这样的表达式,但是这是一个非常不同的故事。

PPS如果列包含数字,则必须根据数字进行测试:而不是('1','1','1')您应该使用(1,1,1)

使用orwhere子句中也可以防止使用索引。 您可以替换查询

select *
  from table
 where <condition1> or <condition2>

select *
  from table
 where <condition1>
 union all
select *
  from table
 where <condition2>

反过来,第二个查询可以产生重复的行(它取决于数据)。 为了防止重复,您可以使用union而不是union all ,但使用union也会引发性能问题。 你需要进行一些实验,这种方式在你的情况下是最好的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM