【发布时间】:2012-01-22 21:49:14
【问题描述】:
有一个查询,通过与另一个表进行比较来将记录设置为坏记录。为了节省时间,我排除了已经标记为“不良”的记录。
我写了一个查询,但不小心检查了 != 'b' 而不是 != 'B'...查询在 0.203 秒内执行。当我意识到我的错误时,我将其更改为 != 'B',但现在查询需要 200 多秒才能执行!!!
当我检查计划时,“b”的优化器选择了两个散列连接的串联。 'B' 的计划选择嵌套循环。
如果重要的话,我的测试没有任何标记为“B”的记录。 gsu.stg_userdata 中有约 18,000 条记录,gsu.userdata_compare 中有约 73,000 条记录。两个查询都得出相同(且正确)数量的结果。
查询:
select gstgu.global_id
from gsu.stg_userdata gstgu
left join gsu.userdata_compare guc
on (gstgu.global_id = guc.global_id) or (gstgu.user_id = guc.user_id)
where gstgu.row_check != 'b'
and ((-- Global IDs match, but two different Network IDs are explicitly set
(gstgu.global_id = guc.global_id) and (guc.user_id is not null and
gstgu.user_id is not null and
guc.user_id != gstgu.user_id))
-- Network IDs match, but two different Global IDs are explicitly set
or (guc.user_id = gstgu.user_id and (guc.global_id is not null and
gstgu.global_id is not null and
guc.global_id != gstgu.global_id))
or length(gstgu.global_id) != 8)
and guc.global_id != '00000000';
--
这条sql的计划:
Cost Card Bytes
SELECT STATEMENT, GOAL = ALL_ROWS 1014 1410 49350
CONCATENATION
HASH JOIN 507 559 19565
TABLE ACCESS FULL GSU STG_USERDATA 205 11144 189448
INDEX FAST FULL SCAN GSU USERCOMPARE_IDX 302 16979 305622
HASH JOIN 507 851 29785
INDEX FAST FULL SCAN GSU USERCOMPARE_IDX 302 16979 305622
TABLE ACCESS FULL GSU STG_USERDATA 205 17949 305133
如果我采用完全相同的查询,然后说
where gstgu.row_check != 'B'
执行需要 200 多秒(将近 1,000 倍的时间),计划如下:
Cost Card Bytes
SELECT STATEMENT, GOAL = ALL_ROWS 507 1 35
NESTED LOOPS 507 1 35
TABLE ACCESS FULL GSU STG_USERDATA 205 1 17
INDEX FAST FULL SCAN GSU USERCOMPARE_IDX 302 1 18
我快疯了,是什么原因??
.
【问题讨论】:
-
有没有匹配
= 'b'的行?您对该列有任何统计信息吗? -
没有一行匹配'b',要么......它们都是'N'。我将不得不查看统计信息...它们现在只是 dev 中的表格,我们通常不会担心统计信息,直到表格在 prod 中。但考虑到“b”和“B”都没有出现在表格中,我想不出有什么重要的原因。
-
“提及”
B或b的陈旧直方图可能会产生与您所看到的一样的奇怪效果。 -
能否给出涉及表的列?
-
最好的办法是使用跟踪来准确验证优化器在做什么 - 将节省您猜测可能发生的事情的时间 - 问题:值 'b' 曾经存在于列中的某个时间点?
标签: sql oracle oracle11g sql-execution-plan