回答

收藏

使用绑定和空值命中Oracle索引的最佳查询

技术问答 技术问答 211 人阅读 | 0 人回复 | 2023-09-14

我有一个表,它在多个列上有一个索引,其中许多是空的。3 I0 a) M. J# J% b4 A+ @- M4 {
CREATE UNIQUE INDEX     UX_MYTABLE_A_B_C_D_E    ON MYTABLE    ("A","B","C","D","E")现在,从C   在代码中,我试图检查表格并准确命中索引。对于每次检查,列表的不同组合可能是NULL。' @# x; i+ `8 M* R
我第一次尝试使用这个查询NVL,但这导致Oracle忽略索引:
( W5 ]0 |2 \7 W6 `" [1 aSELECT * FROM MYTABLE         WHERE NVL(A,0)=:1                                                                                                                                                                                                                                                                                                                                                                                                             AND NVL(B,0)=:2                                   AND NVL(C,0)=:3  3                                                                                                                                                                                                                                                                                                                               AND NVL(D,0)=:4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       AND NVL(E,0)=:5(数据中未使用0。)查询有效,但未命中索引;这是全面扫描。4 `; L0 V2 T- C8 i" s
接下来,我写了自定义C   代码,每次根据搜索条件重新生成查询,并填写IS NULL或填充=:x每一列:
* N' d( d" H7 K5 k! z( V0 q+ ZSELECT * FROM MYTABLE         WHERE A IS NULL          AND B=:1                                                                                                                                                                                                                                                                                                                                                                              AND C IS NULL          AND D=:2                       AND E=:3这也会击中索引,但需要一堆自定义代码并被迫Oracle分析同一基本查询的许多不同变体。如果我每次都要手动组装查询,感觉就像错过了绑定变量的关键点。如果我只有一个查询,它会干净得多。$ a! I* ]0 `9 H6 a1 W2 k
我能写一个查询吗?这个查询可以和NULLs任何组合也可以不与之一起使用s任何组合新索引的情况下使用任何组合,并且总是命中索引?(我意识到我可以NVL(A,0),NVL(B,0)等上加一个功能索引,但对于那些其实应该很简单的东西来说,太可怕了!我试图重用现有的索引,而不是创建新的索引。
/ P7 P. }1 {/ M* e& }/ q$ W                                                               
# \4 f' O5 ~0 r6 C    解决方案:                                                                ; G4 D$ ^+ I) C  R( ]. k8 {' j$ e! n
                                                                您可以比较列和值来检查两者是否为空;或者两者都不是空的和相等的:
. ], G! v( T" CSELECT * FROM MYTABLE WHERE ((A is null and :1 is null) or A = :1)  AND ((B is null and :2 is null) or B = :2)  AND ((C is null and :3 is null) or C = :3)  AND ((D is null and :4 is null) or D = :4)  AND ((E is null and :5 is null) or E = :5)这不是很漂亮,但你应该能够工作。正如你所知,你不能有相等值null与值进行比较只能是is比较运算符。
4 h' ]7 C2 l6 N9 K4 u, B0 R根据客户端软件的不同,您可以使用命名绑定变量来避免重复绑定。如果没有,可以使用接受绑定的子查询或CTE,然后在主查询中使用。
, D, ]* u+ t' {5 R8 T* `9 sWITH CTE AS (  SELECT :1 AS val_1,:2 AS val_2,:3 AS val_3,:4 AS val_4,:5 AS val_5  FROM DUAL)SELECT MT.*FROM CTEJOIN MYTABLE MT  ON ((MT.A is null and CTE.val_1 is null) or MT.A = CTE.val_1)  AND ((MT.B is null and CTE.val_2 is null) or MT.B = CTE.val_2)  AND ((MT.C is null and CTE.val_3 is null) or MT.C = CTE.val_3)  AND ((MT.D is null and CTE.val_4 is null) or MT.D = CTE.val_4)  AND ((MT.E is null and CTE.val_5 is null) or MT.E = CTE.val_5)只要你真的没有任何魔法值为零的列,戈登基于函数的索引方法可能会更可靠、更容易理解。(我也错过了你的问题,没有意识到你已经轻描淡写了。!)
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则