【问题标题】:JPA coalesce / NVL, bind parameters and database index usageJPA coalesce / NVL,绑定参数和数据库索引使用
【发布时间】:2015-08-03 17:45:18
【问题描述】:

当我们想在可空列上使用基于函数的索引时,Oracle 有一种常用方法来使用谓词 NVL(some_column, ' ') = ' ',如下所示:

CREATE INDEX idx_some_index ON some_table (NVL(some_column, ' '));

JPA 中内置的谓词:

criteriaBuilder.equal(criteriaBuilder.coalesce(root.get("some_column"), " "), " ")

hibernate实现(也可以通过eclipse实现)生成的结果SQL谓词:

nvl(sometable0_.some_column, ?)=?

由于使用了第一个绑定参数,它不允许 oracle 使用基于函数的索引。因此,oracle 使用了 FULL SCAN。

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

数字列的类似情况可以正常工作:nvl(sometable0_.some_column, -1)=-1(第二个-1 可以替换为criteriaBuilder.parameter(...),以不强制Oracle 对每个新参数值进行硬解析)。

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

ps。我可以像这样使用我自己的表达式实现(绕过标准构建器构建):

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);
    }

    //...
}

但我不认为这是正确的。

【问题讨论】:

    标签: oracle hibernate jpa coalesce nvl


    【解决方案1】:

    从 11g 开始你可以使用虚拟列

       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 |
    

    获取 some_column 为空或 NULL 的所有记录

    【讨论】:

    • 谢谢。是的,这是 11g 中可能的解决方法。但我正在 JPA 中寻找解决方案,因为在我的情况下,JPA 之上有一些抽象层,并且虚拟列不能在那里使用。
    猜你喜欢
    • 1970-01-01
    • 2010-10-31
    • 1970-01-01
    • 2023-02-03
    • 2010-12-03
    • 2014-07-17
    • 1970-01-01
    • 2017-06-24
    相关资源
    最近更新 更多