我是oracle的新手
我有两个表加入huge_table包含大约10亿行big_table包含大约1亿行,小表包含999行提供过滤条件
small_table.num_id匹配huge_table.num_id列
我注意到的问题是,如果我在where子句中明确提供值,那么使用子查询将比它快得多。
特别是在查看解释计划结果时,此查询的基数为100,成本为6,速度更快
SELECT h.col_required, b.col_required, h.num_id
FROM huge_table h,
big_table b
WHERE h.row_id = b.xx_id
AND b.status = 'up'
AND h.num_id in ('num1', 'num2',... 'num100') -- Explicitly providing the values that in
-- small_table`
带有子查询的查询速度要慢得多,基数为1445704,成本为660293
SELECT h.col_required, b.col_required, h.num_id
FROM huge_table h, big_table b
WHERE h.row_id = b.xx_id
AND b.status = 'up'
AND h.num_id in ('SELECT num_id FROM small_table) -- Using sub query
-- provide the values
我也尝试过使用WHERE exists或INNER JOIN,small_table都提供与子查询类似的结果。
我的问题是,如果没有明确提供where子句中的值,是否可以获得良好的性能?
谢谢
我终于找出了造成这个问题的原因。
在small_table中,num_id的数据类型是NVARCHAR2(255)。虽然在huge_table中,num_id的数据类型是VARCHAR2(255)。
基本上在我转换数据类型后,查询时间减少了。
这个答案是推测性的,但是您所看到的性能的一个可能解释是Oracle在第二个查询中多次在WHERE
子句中执行子查询。也就是说,不是执行一次并缓存结果集,而是多次完成工作。如果使用显式连接重写查询,则可能会解决此问题:
SELECT h.col_required, b.col_required, h.num_id
FROM huge_table h
INNER JOIN big_table b
ON h.row_id = b.xx_id
INNER JOIN small_table s
ON h.num_id = s.num_id
WHERE
b.status = 'up';
您还可以在num_id
上添加以下索引到small_table
:
CREATE INDEX idx ON small_table (num_id);
这可能有助于Oracle更快地完成第二次加入/查找。
你可以试试exists
:
SELECT h.col_required, b.col_required, h.num_id
FROM huge_table h join
big_table b
on h.row_id = b.xx_id
WHERE b.status = 'up' AND
EXISTS (SELECT 1
FROM small_table st
WHERE h.num_id = st.num_id
);
特别是,这可以利用small_table(num_id)
上的索引,以及其他表上的其他索引。