4

16ms〜30msで実行される次のクエリがあります。ハッシュを含むインデックス付き列を検索するcfqueryparamによるクエリが遅い

<cfquery name="local.test1" datasource="imagecdn"> 
    SELECT hash FROM jobs WHERE hash in(
     'EBDA95630915EB80709C69089315399B', 
     '3617B8E6CF0C62ECBD3C48DDF8585466', 
     'D519A38F09FDA868A2FEF1C55C9FEE76', 
     '135F94C3774F7719CFF8FF3A275D2D05', 
     'D58FAE69C559273D8427673A08193789', 
     '2BD7276F209768F2FCA6635659D7922A', 
     'B1E3CFBFCCFF6F5B48A849A050E6D424', 
     '2288F5B8A797F5302E8CA24323617236', 
     '8951883E36B5D38A4643DFAA0396BF13', 
     '839210BD564E30BE1355D1A6D4EF7081', 
     'ED4A2CB0C28B608C29576819CF7BE19B', 
     'CB26925A4874945B810707D5FF0B91F2', 
     '33B2FC229F0CC797A02AD163CDBA0875', 
     '624986E7547DBAC0F47B3005CFDE0A16', 
     '6F692C289BD805CEE41EF59F83F16F4D', 
     '8551F0033C617BD9EADAAD6CEC4B3E9E', 
     '94C3C0A74C2DE085FF9F1BBF928821A4', 
     '28DC1A9D2A69C2EDF5E6C0E6368A0B3C' 
    ) 
</cfquery> 

私は同じクエリを実行しますがでcfqueryparamを使用する場合は、500ミリ秒で実行されます - 2000ミリ秒。

<cfset local.hashes = "[list of the same ids as above]"> 
<cfquery name="local.test2" datasource="imagecdn"> 
    SELECT hash FROM jobs WHERE hash in(
     <cfqueryparam cfsqltype="cf_sql_varchar" value="#local.hashes#" list="yes"> 
    ) 
</cfquery> 

テーブルは、およそ60,000行を有します。 「ハッシュ」列はvarchar(50)で、クラスタ化されていない一意のインデックスを持ちますが、プライマリキーではありません。 DBサーバーはMSSQL 2008です。Webサーバーは最新バージョンのCF9を実行しています。

なぜcfqueryparamがパフォーマンスを爆発させるのでしょうか?ページをリフレッシュした回数に関係なく、毎回このように動作します。リストを2〜3ハッシュだけにペアリングしても、それは150〜200msのようにうまく動作しません。 cfqueryparamを削除すると、パフォーマンスは期待どおりです。このような状況では、SQLインジェクションの可能性があるため、cfqueryparamを使用するのが望ましいでしょうが、インデックス付きの列から2レコードを見つけるのに100msかかるべきではありません。

編集:

  1. 我々はhash()ないのUUIDまたはGUIDSによって生成されたハッシュを使用しています。ハッシュはhash(SerializeJSON({ struct }))によって生成され、画像に実行する一連の操作の計画が含まれています。これは、その構造の正確な一意のIDを挿入前と照会前に知ることができるということです。これらのハッシュは、どの構造体が既にDBに格納されているかの「インデックス」として機能します。さらに、ハッシュで同じ構造体が同じ結果にハッシュされますが、これはUUIDSとGUIDSでは当てはまりません。

  2. クエリは5つの異なるCF9サーバーで実行されており、すべて同じ動作を示します。私にとって、これはCF9が何かをキャッシュしているという考えを排除します。すべてのサーバーがまったく同じDBに接続しているので、キャッシュが発生している場合はDBレベルにする必要があります。

+3

varcharの代わりにcf_sql_charを使用してみましたか? MSSQLが配列を詳しく観察し、より良い実行計画を出すようにするかもしれません。明らかに、キャッシュから来る計画は、リアルタイムでコンパイルする計画ほど効率的ではありません。また、インデックスヒントを追加してみてください。開発システムでトレースアナライザを実行すると、トレースアナライザが実行され、実行計画にいくつかの手がかりが与えられます。それは私が持っているものです:) –

+1

リストのprepare文を再利用することができないため、毎回再コンパイルしている可能性があります。独自のロジックを使用してSQLインジェクションを防ぐことができたら、cfqueryparamこのため。 – Henry

+0

ここではSELECT INのパフォーマンスを向上させるためのいくつかの方法があります。http://florianreischl.blogspot.ca/2012/03/performance-comparison-of-sql-server.html – Henry

答えて

8

問題はVARCHARとNVARCHARに関連している可能性があります。これらの2つのリンクが起こっされる可能性がありますどのような Querying MS SQL Server G/UUIDs from ColdFusionnvarchar vs. varchar in SQL Server, BEWARE

を助けるかもしれcfqueryparamがUnicodeとしてのvarcharを送るかどうColdFusion Administratorで設定があるです。その設定が列の設定と一致しない場合(その場合、その設定が有効な場合)、MS SQLはそのインデックスを使用しません。

+0

私はこの設定をどこで変更するのか、それが正しいかどうかを確認していますか?この特定のデータソースでは、 ''非ラテン文字に設定されたデータソースに対して高ASCII文字とUnicodeを有効にする 'がチェックされていません。したほうがいい?列はvarcharです。 – Nucleon

+0

チェックをはずす必要があるようです。違いがあるかどうかを確認するために設定を変更できますか? – Yisroel

+0

BOOM!それがYisroelです、どうもありがとうございます。私のローカルのデベロッパーボックスで、私はそれをチェックしなかった。私たちのdev/liveサーバー上でそれがチェックされました。チェックを外すと直ちにパフォーマンスがすぐに向上しました。将来同じ問題に遭遇したが、チェックする必要がある場合(ユニコードが必要であったため)、この方法で列がnvarcharになるようにしたいのですが、インデックスもユニコードになりますか? – Nucleon

0

マークが指摘しているように、おそらくキャッシュに悪い実行計画があります。 cfqueryparamの利点の1つは、異なる値を渡すときに、そのステートメントに対してキャッシュされたプランを再利用できることです。このため、小さなリストで試してみると、改善が見られません。 cfqueryparamを使用しない場合、SQL Serverは毎回実行計画を実行する必要があります。これは通常、キャッシュに準最適な計画がない限り、悪いことです。ここで説明したようにキャッシュをクリアしてみてくださいhttp://www.devx.com/tips/Tip/14401これはうまくいけば、次回cfqueryparamでステートメントを実行したときにより良い計画をキャッシュすることを意味します。

意味がありますか?

+1

私は100%は確信していませんがしかし、異なるサイズのリストのための異なる計画です。 CFはSQLを 'SELECT * FROM table WHERE col IN(:listParam)'として渡しません(つまり、単一のバインド・パラメータがあります)、それを 'SELECT * FROM table WHERE col IN(:each、:element、 :別途) '。したがって、サーバーは10要素リストを持つものとは異なる3要素リストのクエリを見るでしょう。そして、それぞれが別々にコンパイルされることを強く疑うでしょう。 –

+1

INステートメントが1つのリストとしてバインドされていないことに私は完全に同意します。しかし、私はそれを新しい準備文として識別し、新しいクエリプランを計算させることはしません。あなたがそれについて考えているなら、INステートメントの項目の数は、テーブルスキャンやインデックスなどを使用するかどうかにはまったく関係がありません。 – baynezy

+0

関連性はありますか?同じクエリが5つの異なるCF9ボックス。それぞれが、Coldfusionのクエリキャッシングの形式を排除すると私は思うのと同じ振る舞いを示しています。すべてのボックスが同じDBに接続されているので、キャッシングがSQLレベルにある可能性があります。 – Nucleon

0

私はcfqueryparamが問題を引き起こしているとは思わない。実行に大きな注目があるので、cfqueryparamで試してみると、あなたのクエリにはインデックスを使用しないことがあります。開発用コンピュータで同じシナリオを作成しましたが、cfqueryparamの有無にかかわらず同じ実行時間があります。あなたはテストとして直接渡している最初のクエリとリストを使用していくつかのオーバーヘッドがあるかもしれませんが、2番目のColdfusionでは、リストからクエリパラメータを作成する必要がありますが、これはあまりありません。私は "SQL Server Profiler"を起動し、サーバー上で実行されるクエリを監視することを提案します。これにより、500 msのコストがかかります。

関連する問題