我在Informix数据库中有一个包含500万条记录的表。
这不是实际的表格,但会显示我遇到的问题。
表:销售额
列:sale_id,sale_confirmed,vendor_id,purchaser_id
索引:idx1(sale_id),idx2(sale_confirmed),idx3(vendor_id),idx4(purchaser_id)
如果我这样做一个查询:
select *
from sales
where sale_confirmed IS NULL
or sale_confirmed = ''
然后查询在大约4或5秒内完成。
如果我这样做一个查询:
select *
from sales
where vendor_id = 12345
or purchaser_id = 12345
然后查询在大约4或5秒内完成。
但是,如果我运行此查询(前两个查询的组合):
select *
from sales
where (sale_confirmed IS NULL
or sale_confirmed = '' )
and (vendor_id = 12345
or purchaser_id = 12345)
然后查询在我取消之前运行了15分钟。
数据库似乎不够聪明,不能串联使用不同的索引,即它似乎无法使用idx2来查找X行数并在该X行数内使用idx3和idx4 - 是的,我会认为这样做足够聪明吗?
在处理WHERE子句的第二部分时,有没有办法强制数据库使用idx3和idx4?
除了创建新索引之外的任何其他解决方案?
感谢。
答案 0 :(得分:2)
尝试使用UNION,其中每个部分只需要选择两个索引:
select *
from sales
where (sale_confirmed IS NULL
or sale_confirmed = '' )
and vendor_id = 12345
UNION
select *
from sales
where (sale_confirmed IS NULL
or sale_confirmed = '' )
and purchaser_id = 12345
如果Informix支持内联视图,请根据供应商/购买者获取行集,然后从该集合中排除未经证实的销售。
select inlineview.* from
(
select * from sales
where vendor_id = 12345 or purchaser_id = 12345
) as inlineview
where (sale_confirmed IS NULL or sale_confirmed = '')
最后,我想您可能希望在sale_confirmed上删除低基数指数。
P.S。我通常在我的数据库中没有允许空字符串,NULL和其他值的列。如果有的话,我可能会将字段限制为BIT类型,1和0,默认为0。
答案 1 :(得分:1)
'sale_confirmed'上的索引不太可能有用,因为'sale_confirmed'的基数似乎很低(NULL,是,否?)。更好的模式设计会在'sale_confirmed'上强制执行NOT NULL,并且CHECK约束会强制执行'Y'或'N',默认情况下可以给你'N',除非您另有指定。这样就可以避免在'sale_confirmed'上进行OR操作,这很麻烦。
Tim建议的UNION技术可能是一个不错的解决方法。