これは私に興味をそそられたので、私は少し基本的なテストをしました。いくつかの異なる値といくつかの繰り返し値を含む小さなテーブルを作成しました。これは、文字列の連結を行うだけの関数であり、次の実行プランを確認しました。
Go
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
select distinct cola, colb, dbo.sillyfunc(cola, colb)
from distincttest
--Clear the cache
Go
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
select cola, colb, dbo.sillyfunc(cola, colb)
from (select distinct cola, colb from distincttest) as t
この場合、実行プランは、最初のプランがすべての単一行に対して連結関数を実行したことを明確に示していましたが、2番目のプランは最初に個別の値の並べ替えを実行し、次に関数を実行しました。ただし、少数の行の場合、実行時間は同じであり、一緒に実行すると、クエリリソース全体の50%を使用して各行が表示されました。
そこで、数十万の繰り返し行を追加しました。もう一度やり直しました。これによりクエリプランが変更され、以前の並べ替えではなく、区別を取得するためにハッシュ一致が実行されました。現在、区別を選択するように強制された2番目のバージョンでは、最初に10倍以上高速に実行されました。
最後に、SQL Serverでsillyfuncが非決定論的(0を返す)としてマークされているためである可能性があると考えたため、組み込み関数で決定論的と見なされるpatindexselect OBJECTPROPERTYEX(object_id('dbo.sillyfunc'), 'isdeterministic')
に切り替えました。これにより、最初のバージョンではすべての行に対して、2番目のバージョンではいくつかの異なる行に対して関数が呼び出されても同じ結果が得られました。
したがって、さらにテストを行うと、オプティマイザーがより洗練された処理を実行するように誘導する状況が見つかる可能性がありますが、関数が呼び出される前に個別を適用する場合は、サブクエリ、CTE、または関数がアクセスできるものを制限するための一時テーブル。