2

NVL(some_column, ' ') = ' '次のように、null 許容列で関数ベースのインデックスを使用する場合、Oracle には述語を使用する一般的な方法があります。

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

JPAで構築された述語:

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

休止状態の実装によって生成された結果の SQL 述語 (Eclipse の実装によっても):

nvl(sometable0_.some_column, ?)=?

最初のバインド パラメータを使用するため、オラクルは関数ベースのインデックスを使用できません。その結果、Oracle は FULL SCAN を使用します。

コード ( ) によると、LiteralExpression.render(...)JPA 実装は、すべての文字列リテラル (非数値リテラル) のバインド パラメーターを作成します。このアプローチを使用して、SQLインジェクションの可能性を回避していると思います...

数値列の同様のケースは正常に機能します: nvl(sometable0_.some_column, -1)=-1(2番目は、新しいパラメータ値ごとにOracleにハード解析を強制しない-1ように置き換えることができます)。criteriaBuilder.parameter(...)

だから私の質問:インジェクションが不可能であると確信している場合に、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);
    }

    //...
}

しかし、私はこれが正しいとは考えていません。

4

1 に答える 1

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 のすべてのレコードを取得するには

于 2015-08-03T20:27:32.423 に答える