Я подозреваю, что это в конечном итоге станет проблемой проектирования базы данных, а не проблемой оптимизации запросов. Тем не менее, шаги для анализа этого запроса были изложены выше. Для повторения:
0) Принимая во внимание логику вашего приложения, вам может не понадобиться выполнять этот запрос почти столько же раз, сколько в настоящее время, либо вы можете обнаружить, что вам не нужны данные в том же формате, в котором вы сейчас находитесь производя его, позволяя вам написать более простой и быстрый запрос. Я собираюсь предположить, что вам нужен этот запрос.
1) сгенерировать план выполнения для запроса для пробного прогона. (нажмите кнопку включения плана выполнения или Ctrl + m)
Ищите части плана выполнения, которые требуют много работы, и посмотрите, сможете ли вы связать их с определенной частью запроса. Это даст нам подсказку о том, где сосредоточить наши усилия.
Поиграйте с этими частями запроса и посмотрите, что вы можете придумать.
Одна вещь, которая, как я вижу, может повысить производительность (в зависимости от специфики ваших данных), это попытаться установить порядок доступа данных к таблице DettaglioOrariLinee. Например:
;WITH DettaglioOrariLineePeriodi AS
(
SELECT Orario, IDDettaglioOrariLinee, IDOrario
FROM DettaglioOrariLinee
WHERE IDOrario IN ( SELECT IDOrario --This is still an inner join
FROM Periodi
WHERE
(
@Data = 0 OR
(
@Data >= CAST(CAST(DATEPART(DAY, PeriodoDal) AS VARCHAR)+'/'+ CAST(DATEPART(MONTH, PeriodoDal)AS VARCHAR) +'/'+ CAST(DATEPART(YEAR,@Data)AS VARCHAR) AS DATETIME)
AND
@Data <= CAST(CAST(DATEPART(DAY, PeriodoAl) AS VARCHAR)+'/'+ CAST(DATEPART(MONTH, PeriodoAl)AS VARCHAR) +'/'+ CAST(DATEPART(YEAR,@Data)AS VARCHAR) AS DATETIME)
)
)
)
)
SELECT
OrarioA,
OrarioB,
IDOrario,
IDDettaglioOrarioA,
IDDettaglioOrarioB
FROM
(
SELECT
Tb_01.Orario AS OrarioA,
Tb_02.Orario AS OrarioB,
Tb_01.IDDettaglioOrariLinee AS IDDettaglioOrarioA,
Tb_02.IDDettaglioOrariLinee AS IDDettaglioOrarioB,
Tb_01.IDOrario,
ROW_NUMBER() OVER (PARTITION BY Tb_01.Orario, Tb_02.Orario ORDER BY Tb_01.IDOrario DESC) AS Row
FROM
(
SELECT Orario, IDDettaglioOrariLinee, IDOrario
FROM DettaglioOrariLineePeriodi --NEW CTE
WHERE IDRelLineeStazionamenti = @IDRelA
) AS Tb_01
INNER JOIN
(
SELECT Orario, IDDettaglioOrariLinee, IDOrario
FROM DettaglioOrariLineePeriodi --NEW CTE
WHERE IDRelLineeStazionamenti = @IDRelB
) AS Tb_02
ON Tb_01.IDOrario = Tb_02.IDOrario
INNER JOIN --dbo.relgiornisettimanaorarilinee ON Tb_01.IDOrario = dbo.relgiornisettimanaorarilinee.IDOrario
(
SELECT IDOrario
FROM relgiornisettimanaorarilinee
WHERE @IDGiorno = 0 OR IDGiorno = @IDGiorno
) Tb_Giorni
ON Tb_01.IDOrario = Tb_Giorni.IDOrario
WHERE
(
@Orario = '' OR DATEDIFF(minute, CAST(@ORARIO AS DATETIME), CAST(Tb_01.Orario AS DATETIME)) >=0
) AND (
DATEDIFF(minute, CAST(Tb_01.Orario AS DATETIME), CAST(Tb_02.Orario AS DATETIME)) >=0
) AND (
@IDOrari = '' OR Tb_01.IDOrario NOT IN (SELECT CAST(s AS INT) AS IDOrario FROM dbo.Split(',', @IDOrari) AS Split_1)
)
/*
AND
(
@Data = 0
OR
(
@Data >= CAST(CAST(DATEPART(DAY, PeriodoDal) AS VARCHAR)+'/'+ CAST(DATEPART(MONTH, PeriodoDal)AS VARCHAR) +'/'+ CAST(DATEPART(YEAR,@Data)AS VARCHAR) AS DATETIME)
AND
@Data <= CAST(CAST(DATEPART(DAY, PeriodoAl) AS VARCHAR)+'/'+ CAST(DATEPART(MONTH, PeriodoAl)AS VARCHAR) +'/'+ CAST(DATEPART(YEAR,@Data)AS VARCHAR) AS DATETIME)
)
)
AND
(@IDGiorno = 0 OR IDGiorno = @IDGiorno)
*/
) As Tb_New
WHERE ROW = 1
OPTION (MAXRECURSION 0);
Другая вещь, которую вы могли бы попробовать, это заменить строку
@IDOrari = '' OR Tb_01.IDOrario NOT IN (SELECT CAST(s AS INT) AS IDOrario FROM dbo.Split(',', @IDOrari) AS Split_1)
С
@IDOrari = '' OR (@IDOrari NOT LIKE Tb_01.IDOrario + ',%' AND @IDOrari NOT LIKE '%,' + Tb_01.IDOrario + ',%' AND @IDOrari NOT LIKE '%,' + Tb_01.IDOrario)
3) Если вы не можете найти ничего, что помогает, или у вас есть куча табличных сканирований, следующим шагом будет посмотреть, можете ли вы изменить индексы для этих таблиц. Я бы порекомендовал загрузить профилировщик SQL (вам может понадобиться установить его с вашего диска sql) и создать новую трассировку. Как только трассировка началась, выполните операцию, которая занимает слишком много времени, а затем остановите трассировку. Сохраните трассировку в файл, а затем запустите советник по настройке ядра базы данных. Загрузите файл, выберите базу данных для настройки и нажмите «Начать трассировку».
Надеюсь, это даст вам список рекомендаций. Я бы сосредоточился на изменениях таблицы DettaglioOrariLinee и любой другой таблицы, которая занимала большую часть плана выполнения с помощью операции сканирования.
Я бы настоятельно рекомендовал не применять рекомендуемые изменения прямо из этого инструмента, вместо этого используйте эти рекомендации в качестве руководства.
4) Если ничего из вышеперечисленного не даст вам необходимого улучшения производительности, вы можете изучить денормализацию таблицы DettaglioOrariLinee, чтобы в каждой строке были данные для сторон A и B. Это, вероятно, не очень хорошая идея.