4

射影 (SELECT された出力)、ORDER BY、および WHERE 句の 3 つの場所で使用したいサブクエリ ( LastActivityOn ) があります。

SELECT TOP 175
  (SELECT MAX(ActivityDate) FROM (VALUES
    (UserRegistration.CreatedOn),
    (UserRegistration.ActivatedOn),
    (UserRegistration.LastLoginOn),
    (UserRegistration.UpdatedOn),
    (UserProfile.LastPostedOn)) AS AllDates(ActivityDate)) LastActivityOn,
  UserRegistration.FirstName,
  UserRegistration.LastName,
  [15 more columns of various calculated distances, coalesces, etc...]
FROM
  UserRegistration
  INNER JOIN UserProfile ON UserRegistration.Id = UserProfile.RegistrationId
  INNER JOIN (
    SELECT PostalCode, GeoCenter, PrimaryCity, StateOrProvince
    FROM PostalCodes 
    WHERE @OriginPostalCode IS NULL OR PostalCodes.GeoCenter.STDistance(@OriginPoint) < @WithinMeters
  ) AS ProximalPostalCodes ON ProximalPostalCodes.PostalCode = UserRegistration.PostalCode
  [7 more joins including full-text queries]
WHERE
  LastActivityOn > @OldestUserToSearch AND
  [20 more lines of filtering logic]
ORDER BY
  LOG(DATEDIFF(WEEK, LastActivityOn, @Today))/LOG(2),
  FullTextRelevance

LastActivityOn が 3 回発生していることに注意してください。また、LastActivityOn サブクエリは 2 つのテーブルを参照することに注意してください。親クエリの結合句に依存しているため、本質的に相関サブクエリですか?

ユーザー定義関数を介して最大 2 つの日付のみを取得していたとき、結果の値を WHERE および ORDER BY で使用できました。現在、私はできません。

いくつかのオプションがあるようです...すべてを別のクエリでラップし、追加されたアクティビティだけで射影を繰り返すことができます。同じように "WITH" (CTE) を使用できるようです。

しかし、サブクエリを思いどおりに使用できる場合と使用できない場合のルールを明確に理解していないため、簡単に何かを見落としている可能性があります。何か案は?

それとも、SQL SERVER は出力行ごとに 1 回だけ計算を実行するほどスマートであり、心配する必要はないのでしょうか?

編集: 現在 SQL Server 2008 Standard を実行していますが、アップグレードはある時点で順番に行われます。また、RE: ログ関数 - 加重合計としての関連性と組み合わせる作業を行っているため、これは進行中の作業です。ランキングの一種として使用するために INT でトリミングするか、線形調整で関連性を追加します。

訂正: ORDER BY でサブクエリ エイリアスを使用できましたが、追加の計算や where 句では使用できませんでした。それを指摘してくれたypercubeに感謝します。

4

3 に答える 3

6

クエリを変更しようとはしませんが、一般的なテーブル式が必要な場合があります。

于 2012-08-06T10:44:51.100 に答える
2

この参加を含めると、必要なことができると思います。

OUTER APPLY (SELECT MAX(ActivityDate) LastActivityOn FROM (VALUES
    (UserRegistration.CreatedOn),
    (UserRegistration.ActivatedOn),
    (UserRegistration.LastLoginOn),
    (UserRegistration.UpdatedOn),
    (UserProfile.PostedOn)) AS AllDates(ActivityDate)) LastActivity

また、条件付きWHERE基準として追加し、NULLパラメーターで無効にします。

WHERE
  (@OldestUserToSearch IS NULL OR
  LastActivityOn > @OldestUserToSearch) AND

結果

これを使用してSELECTで参照するパフォーマンスは、SQLServer2008の副選択と同じでした。

WHERE述語を追加すると、問題が発生し始めます。元の質問で確認できる郵便番号半径検索は、計算の最も重い部分であり、「TOP175」に最も近い検索の上部で最も効果的に機能しました。残念ながら、オプティマイザーは、「OUTER APPLY」出力を複数の場所で再利用したときに、距離計算が最終的にさらに多くの行に対して実行される実行プランの5レベル深くに移動しました。その結果、クエリは約6倍の長さで実行されました。

同じ形状のクエリでもパフォーマンスは同じであり、コードも少なくなるため(投影を修正したり、クエリ全体をCTEまたはサブクエリでラップしたりする必要がない)、探していた答えをOUTERAPPLYと呼びます。これとは別に、すべての状況でGIS検索を最も外側のネストされたループに強制する必要がある場合は、そのクエリを再定式化する必要があります。

提示されたオプションの概要:同じ選択で計算された式を複数回繰り返さないようにするにはどうすればよいですか?

APPLYのいくつかの有用な同様の使用法:

サブクエリとCTEに関するローカルの例(回答として拒否しました):

関連するタイトルの関連のない/役に立たない記事:

于 2012-08-06T12:35:15.210 に答える