甲骨文 11g R2
不幸的是,我们的应用程序具有每行安全“功能”。我们有一个看起来像这样的查询:
坏,慢:
SELECT someRow, someOtherRow
FROM bigTableA a
WHERE EXISTS (
SELECT 0 FROM bigTableA_securitymapping b
WHERE b.PrimaryKeyTableA = a.PrimaryKeyTableA AND
b.accesscode in (SELECT accesscode
FROM accesscodeView
WHERE user = :someUserID)
)
Run Code Online (Sandbox Code Playgroud)
上有一个唯一索引bigTableA_securitymapping(PrimaryKeyTableA,accesscode)
。
将accesscodeView
有可能返回多个accesscode给定用户,所以它必须是IN()
不=
。
问题是此查询忽略了唯一索引bigTableA_securitymapping
并选择执行全表扫描。
如果我将 the 更改IN()
为 an=
那么它会UNIQUE SCAN
在唯一索引上执行 abigTableA_securitymapping
并且大约快 50 倍。
好,快但不可能:
SELECT someRow, someOtherRow
FROM bigTableA a
WHERE EXISTS (
SELECT 0 FROM bigTableA_securitymapping b
WHERE b.PrimaryKeyTableA = a.PrimaryKeyTableA AND
b.accesscode =(SELECT distinct accesscode
FROM accesscodeView
WHERE user = :someUserID)
)
Run Code Online (Sandbox Code Playgroud)
但是,我不能这样做,因为accesscodeView
可能返回多于一行。
(那里有一个distinct
,因为accesscodeView
它给出了需要=
,将DISTINCT
放在原始查询上没有区别。)
如果我对访问代码进行硬编码,它也会UNIQUE SCAN
对bigTableA_securitymapping
.
好,快,但需要大量的应用程序更改:
SELECT someRow, someOtherRow
FROM bigTableA a
WHERE EXISTS (
SELECT 0 FROM bigTableA_securitymapping b
WHERE b.PrimaryKeyTableA = a.PrimaryKeyTableA AND
b.accesscode in (1,2,3,4)
)
Run Code Online (Sandbox Code Playgroud)
更改为内部连接也无济于事。它仍然进行全表扫描。
坏,慢:
SELECT someRow, someOtherRow
FROM bigTableA a
WHERE EXISTS (
SELECT 0 FROM accesscode ac INNER JOIN
bigTableA_securitymapping b ON
ac.accesscode = b.accesscode
WHERE b.PrimaryKeyTableA = a.PrimaryKeyTableA
AND user = :someUserID
)
Run Code Online (Sandbox Code Playgroud)
那么为什么=
和IN()
in之间存在差异。为什么不相关的子查询(accesscodeview
子查询)会导致这样的计划差异?有什么办法可以重写它来做我想做的事吗?此处“好计划”成本与“坏计划”成本的差异是 87 和 37,000,并且在实际运行时需要大量时间才能获得相同的结果。
小智 -1
这就是我要做的,尽管我并没有完全看到这里的全貌,也许我错过了一些东西。如果它没有用,一个例子将有助于完善我的答案。
SELECT someRow, someOtherRow
FROM bigTableA a
WHERE EXISTS (
SELECT 0 FROM bigTableA_securitymapping b
WHERE b.PrimaryKeyTableA = a.PrimaryKeyTableA
AND EXISTS (SELECT 1 FROM accesscodeView
WHERE user = :someUserID
AND accesscode = b.accesscode)
)
Run Code Online (Sandbox Code Playgroud)
它总是返回一行而不是扫描一秒(或更多,如果有更多)
归档时间: |
|
查看次数: |
111 次 |
最近记录: |