この選択で1回のシークで同じ結果を取得する方法はありますか?


8

クエリを変更するか、オプティマイザの戦略に影響を与えることにより、1回のシークまたはスキャンで次と同じデータを取得することは可能ですか?

これに類似したコードとスキーマは現在SQL Server 2014にあります。

ここに画像の説明を入力してください

再現スクリプト。セットアップ:

USE tempdb;
GO
IF OBJECT_ID('dbo.TestUpload', 'U') IS NOT NULL 
  DROP TABLE dbo.TestUpload; 


CREATE TABLE dbo.TestUpload(
    JobRunId bigint NOT NULL,
    ThingAName nvarchar(255) NOT NULL,
    ThingAType nvarchar(255) NOT NULL,
    ThingAGranularity nvarchar(255) NOT NULL,
    ThingBName nvarchar(255) NOT NULL,
    ThingBType nvarchar(255) NOT NULL,
    ThingBGranularity nvarchar(255) NOT NULL
);
CREATE CLUSTERED INDEX IX_JobRunId ON dbo.TestUpload (JobRunId);

GO

INSERT INTO dbo.TestUpload (JobRunId, ThingAName, ThingAType, ThingAGranularity, ThingBName, ThingBType, ThingBGranularity)
  VALUES (1, 'A', 'B', 'C', 'D', 'E', 'F');
GO 10

INSERT INTO dbo.TestUpload (JobRunId, ThingAName, ThingAType, ThingAGranularity, ThingBName, ThingBType, ThingBGranularity)
  VALUES (1, 'D', 'E', 'F', 'A', 'B', 'C');
GO 10

クエリ:

DECLARE @JobRunID bigint = 1;

SELECT JobRunId,
  ThingAName AS Name, 
  ThingAType AS [Type], 
  ThingAGranularity AS Granularity
FROM dbo.TestUpload
WHERE JobRunId = @JobRunID
UNION
SELECT JobRunId,
  ThingBName AS Name, 
  ThingBType AS [Type], 
  ThingBGranularity AS Granularity
FROM dbo.TestUpload
WHERE JobRunId = @JobRunID;

取り壊す:

IF OBJECT_ID('dbo.TestUpload', 'U') IS NOT NULL 
  DROP TABLE dbo.TestUpload;

これはおそらく理想的にモデル化されていないと思います。スキーマがどのように選択されたかについて開発者からより多くの情報を取得しようとしていますが、スキーマよりもクエリを変更する方が簡単なので、見落としているTSQLのトリックがあるかどうか知りたいです。

回答:


6

私はこれを試しますが、それがより効率的になるかどうかはわかりません。あなたが必要とするDISTINCTので、重複を削除するUNION ALL方が適切かもしれないが、二つの別個の操作は必要ありません。

SELECT DISTINCT 
    JobRunId = @JobRunID, 
    d.*
FROM dbo.TestUpload
  CROSS APPLY 
    (   SELECT 
          ThingAName AS Name, 
          ThingAType AS [Type], 
          ThingAGranularity AS Granularity
      UNION                            -- or UNION ALL
        SELECT 
          ThingBName, 
          ThingBType, 
          ThingBGranularity
    ) AS d 
WHERE JobRunId = @JobRunID ;

UNION ALL 予定:

UNION ALLプラン

UNION 予定:

UNIONプラン


3

クロス適用を使用して列を行にアンピボットする

SELECT --DISTINCT most probably
  JobRunId,
  ut.Name, 
  ut.[Type], 
  ut.Granularity
FROM dbo.TestUpload
CROSS APPLY (
  SELECT ThingBName AS Name, 
  ThingBType AS [Type], 
  ThingBGranularity AS Granularity
  UNION ALL 
  SELECT ThingAName AS Name, 
  ThingAType AS [Type], 
  ThingAGranularity AS Granularity
  ) ut
WHERE JobRunId = @JobRunID

1
いいえ、私は同じことを考えましたが、これはうまくいきません。UNION削除しなければならない重複があるのでさえありません。
ypercubeᵀᴹ

ソートは避けられないということですか?
Serg

1
つまりDISTINCT必要です。Jamesのデータを参照してください。行がでありますA,B,C,-,-,-し、他と-,-,-,A,B,C。結果の行の1つはAデータから、もう1つはBデータからのものであり、削除する必要があります。場合でもUNION ALL、ISはと交換しUNION、これを回避することはできません。(そして「これ」とは、「ソート」を意味するのではなく、「別個の」操作を意味します。オプティマイザが実行および選択できる方法が何であれ、ソートまたはハッシュで実行される可能性があります。)
ypercubeᵀᴹJun
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.