Oracle JPA coalesce/NVL、绑定参数和数据库索引使用

Oracle JPA coalesce/NVL、绑定参数和数据库索引使用,oracle,hibernate,jpa,coalesce,nvl,Oracle,Hibernate,Jpa,Coalesce,Nvl,Oracle中有一种常见的方法,当我们希望对可空列使用基于函数的索引时,可以使用谓词NVL(some_column',)=',如下所示: CREATE INDEX idx_some_index ON some_table (NVL(some_column, ' ')); public class UnsafeLiteralExpression<T> extends ExpressionImpl<T> implements Serializable { @Supp

Oracle中有一种常见的方法,当我们希望对可空列使用基于函数的索引时,可以使用谓词
NVL(some_column',)='
,如下所示:

CREATE INDEX idx_some_index ON some_table (NVL(some_column, ' '));
public class UnsafeLiteralExpression<T> extends ExpressionImpl<T> implements Serializable {
    @SuppressWarnings({ "unchecked" })
    public UnsafeLiteralExpression(T literal) {
        this((Class<T>) determineClass( literal ), literal );
    }

    public UnsafeLiteralExpression(Class<T> type, T literal) {
        super(null, type );
        this.literal = literal;
    }

    //...

    public String render(CriteriaQueryCompiler.RenderingContext renderingContext) {
        return renderProjection(renderingContext);
    }

    //...
}
JPA中内置的谓词:

criteriaBuilder.equal(criteriaBuilder.coalesce(root.get("some_column"), " "), " ")
hibernate实现(也是eclipse实现)生成的结果SQL谓词:

由于使用第一个绑定参数,它不允许oracle使用基于函数的索引。因此,oracle使用完全扫描

根据代码(
LiteralExpression.render(…)
),JPA实现为所有字符串文本(非数字文本)创建绑定参数。我认为它使用这种方法来避免可能的SQL注入

与数字列类似的情况也适用:
nvl(sometable0\uu.some\u列,-1)=-1
(第二个
-1
可以替换为
criteriaBuilder.parameter(…)
,不强制Oracle对每个新参数值进行硬解析)

所以我的问题是:在我绝对确定注入不可能的情况下,有没有任何法律方法可以强制JPA不使用bind参数

另外,我可以使用自己的表达式实现(绕过标准生成器构建),如下所示:

CREATE INDEX idx_some_index ON some_table (NVL(some_column, ' '));
public class UnsafeLiteralExpression<T> extends ExpressionImpl<T> implements Serializable {
    @SuppressWarnings({ "unchecked" })
    public UnsafeLiteralExpression(T literal) {
        this((Class<T>) determineClass( literal ), literal );
    }

    public UnsafeLiteralExpression(Class<T> type, T literal) {
        super(null, type );
        this.literal = literal;
    }

    //...

    public String render(CriteriaQueryCompiler.RenderingContext renderingContext) {
        return renderProjection(renderingContext);
    }

    //...
}
public类UnsafeLiteralExpression扩展了ExpressionImpl实现可序列化{
@SuppressWarnings({“unchecked”})
公共非恰当表达(T文字){
这个((类)determineClass(literal),literal);
}
public UnsafeLiteralExpression(类类型,T literal){
super(null,type);
this.literal=literal;
}
//...
公共字符串呈现(CriteriaQueryCompiler.RenderingContext RenderingContext){
返回renderproject(renderingContext);
}
//...
}

但是我不认为这是正确的。

< P>从11G开始,你可以使用虚拟列< /P>
   some_column_nvl VARCHAR2(10) GENERATED ALWAYS AS (NVL(some_column,' ')) VIRTUAL,
并在此列上使用普通索引

create index test_idx on test(some_column_nvl);
虚拟列处理数据库中的NVL,因此您可以进行简单查询:

 criteriaBuilder.equal(root.get("some_column_nvl"), " ")
使用索引

 |*  2 |   INDEX RANGE SCAN                  | TEST_IDX |     2 |       |     1   (0)| 00:00:01 |

要获取某些列为空或空的所有记录,请参见

谢谢。是的,这是11g中可能的解决方法。但我正在寻找JPA中的解决方案,因为在我的例子中,JPA上面有一些抽象层,虚拟列不能在那里使用。