4

couchbaseクエリプランの仕組みの理解に問題があります。 SpringDataをCouchbase 4.1で使用し、Couchbaseリポジトリのカスタム実装を提供します。私は法の下に持っているCouchbaseのリポジトリの私のカスタムimplememtnation内部:結果でCouchbaseはN1QLのパラメータ化クエリで間違ったインデックスを使用します

String queryAsString = "SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS FROM MyDatabase WHERE segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1"; 
JsonObject params = JsonObject.create() 
     .put(CLASS_VARIABLE, MyClass.class.getCanonicalName()) 
     .put(ID_VARIABLE, segmentId); 

N1qlQuery query = N1qlQuery.parameterized(queryAsString, params); 
List<MyClass> resultList = couchbaseTemplate.findByN1QL(query, SegmentMembers.class); 
return resultList.isEmpty() ? null : resultList.get(0); 

、春データはCouchbaseのにクエリを表し、次のJSONオブジェクトを生成します。私は、実行時に

{ 
    "$class":"path/MyClass", 
    "statement":"SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS from MyDatabase where segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1", 
    "id":"6592c16a-c8ae-4a74-bc17-7e18bf73b3f8" 
} 

そして、問題はパフォーマンスでありますそれはJavaとN1QL Rest APIを介して、またはcbqコンソール経由で。このクエリをcbqで実行するには、パラメータ参照を正確な値に置き換えます。

selectステートメントの前にEXPLAIN句を追加した後、私は別の実行計画を述べました。 JavaのSpringデータまたはN1QLのRest APIを使用して、このクエリをパラメータ化されたクエリとして実行しました。このケースでは、クエリで作成したインデックスは使用されません。インデックスdefinitonは以下見つけることができます:

CREATE INDEX `testMembers` ON MyDatabase `m`(`_class`,`segmentId`,`executionTime`) WHERE (`_class` = "path/MyClass") USING GSI; 

私はCBQ卓を経由してクエリを実行すると、そう、Couchbaseのが私のidnexを使用すると、クエリのパフォーマンスは非常に良いです。しかし、N1QLの残りのAPIまたはJavaを介してこのクエリを実行すると、そのクエリがインデックスを使用しないことがわかります。あなたはこの事実を証明する実行計画の一部で見ることができます:だから

"~children": [ 
{ 
    "#operator": "PrimaryScan", 
    "index": "#primary", 
    "keyspace": "CSM", 
    "namespace": "default", 
    "using": "gsi" 
}, 

を、質問はその権利とCouchbaseのクエリオプティマイザの法的な挙動がありますか?クエリプランではパラメータの実際の値が考慮されないということですか?そして、私は手動でクエリ文字列に値を入れたり、正しいインデックス選択でN1Qlのパラメータ化されたクエリを使用するために他の方法で存在していますか?

EDIT

シャシのラジの答えによると、私は(N1qlParams.buildを追加)N1QLクエリをパラメータ化する。アドホック(偽)パラメータ。私はまだこのクエリでパフォーマンスの問題があるので、これは私の問題を解決しません。さらに、私がクエリを印刷するとき、私は以前に説明したのと同じことが分かります。だから、私のクエリはまだ間違って分析し、パフォーマンスの低下を引き起こします。

+0

あなたは、これが修正されているかどうかを確認するためにCouchbaseの4.5.1を試すことができます。 – geraldss

+0

ナー、それは4.6で固定されていない – gaperton

+0

そして明らかに、修正するものはありません。下の私の答えを見てください。 – gaperton

答えて

1

問題は、あなたが「どこ」節WHERE (_class = "path/MyClass")、そして同時に、あなたはあなたのクエリにパラメータとして_classを渡すと、インデックスを持っていることに起因します。

したがって、パラメータ化クエリを分析クエリオプティマイザは、このクエリは、_class = "path/MyClass"用に作成されたインデックスを使用する選択はどこだ、それは_class = $classのだ引き起こす可能性があるという考えを持っていません。かなり簡単ですね。

したがって、インデックスの 'where'を選択パラメータとして指定したフィールドは渡さないでください。代わりにcreate indexの場合と同じ方法で、ハードコード_class = "path/MyClass"を選択してください。そしてすべてがうまくいくはずです。

ここには、それに関するcouchbase問題追跡システムのチケットがあります。

https://issues.couchbase.com/browse/MB-22185?jql=text%20~%20%22parameters%20does%20not%20use%20index%22

2

クエリとして渡す必要がありますどのように動作するかN1QLパラメータ化クエリを知るために必要なすべての最初:

jsonObjectは、すべての必要があります
N1QL.parameterized(query,jsonObject,N1qlParams.build().adhoc(false)); 

String query= select * from bucketName where _class=$_class and segmentId=$segmentId LIMIT $limit ; 

今クエリとして渡す必要がありますプレースホルダ値。

JsonObject jsonObject=JsonObject.create().put("_class","com.entity,user").put("segmentId","12345").put("limit",100); 

N1qlParams.build().adhoc(false)あなたのクエリを最適化する場合は、それを利用しますので、省略可能です。それはLRUを使用して、以前に入力されたクエリを追跡し、それを記録して、次回はクエリを解析する必要がなく、以前のプリペアドステートメントからフェッチする必要はありません。

唯一の問題は、couchbaseが最後に検索された5000件のレコードしか保持しないことです。あなたのケースで

+0

申し訳ありませんが、これは私の問題を解決しませんでした。私はこのフラグをfalseに設定してクエリを作成しても、まだパフォーマンスの問題があります。 他にも提案がありますか? – 4the3eam

+0

カバー索引を使用してみてください。パフォーマンスの問題のほとんどが解決されます。 5つの属性を使用してクエリを行いたい場合は、インデックスを作成するときにこれらの属性を指定してください。 –

+0

クエリのJsonオブジェクトの変数の作成が同じである必要があります。それ以外の場合は動作しません。 –

関連する問題