Есть ли способ сделать так, чтобы этот выбор извлекал одинаковые результаты одним поиском?


8

Можно ли получить те же данные, что и следующие, с помощью одного поиска или сканирования, либо изменив запрос, либо повлияв на стратегию оптимизатора?

Код и схема, подобные этой, в настоящее время используются в 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требуется. Смотрите данные Джеймса. Есть ряд с, A,B,C,-,-,-а другой с -,-,-,A,B,C. Результирующие строки, одна из данных A, а другая из данных B, идентичны и должны быть удалены. Даже если UNION ALLзаменить его UNION, этого нельзя избежать. (и под «этим» я не подразумеваю «сортировку», я имею в виду «отличную» операцию. Это может быть сделано с помощью сортировки или хеширования, каким бы способом ни оптимизатор мог и не выбрал.)
ypercubeᵀᴹ
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.