我有这个查询,我想提高性能:
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 DettaglioOrariLinee
WHERE IDRelLineeStazionamenti = @IDRelA
) AS Tb_01
INNER JOIN
(
SELECT Orario, IDDettaglioOrariLinee, IDOrario
FROM DettaglioOrariLinee
WHERE IDRelLineeStazionamenti = @IDRelB
) AS Tb_02
ON Tb_01.IDOrario = Tb_02.IDOrario
INNER JOIN
(
SELECT IDOrario
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)
)
)
) Tb_Periodi
ON Tb_01.IDOrario = Tb_Periodi.IDOrario --dbo.periodi ON Tb_01.IDOrario = dbo.periodi.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);
我想用IDOrario过滤Tb_Periodi和Tb_Giorni。
如何改进此查询?
是。我正在使用sql server 2005.它的查询被多次调用,每次请求50次,这是for-cycle。是否可以使用缓存。我不知道提高性能。我已经尝试了一切!
我注意到一些查询在循环中重复多次,根据你的意思我该如何利用它?
答案 0 :(得分:3)
在优化性能时,通常更好(更容易)衡量瓶颈的位置。您是否尝试过使用Query Analyzer?
答案 1 :(得分:1)
看看执行计划,看看它在做什么。你可能会发现一些索引会有所帮助,但看看那段代码我怀疑它会那么简单。
有助于提高性能的一件事就是改变您的结构,以便在日期时间数据类型中正确存储日期。这将摆脱很多演员和转换的东西whihc必须在每一行上行动,特别是在where子句中,它必须将这些东西连接成每一行的日期以便应用where条件。如果您正在进行任何数据操作,则必须存储为datetime数据类型,否则您可能会遇到性能不佳的情况。
答案 2 :(得分:1)
好的,
查询实际上是否有效?没有必要尝试提高返回错误结果集的查询的性能。
您是否有可以比较的已知结果集的测试计划列表。 SQL查询改进是测试驱动开发的一个非常好的例子,因为在重新构造查询时很容易引入错误(错误的结果)。
描述您希望查询在英语中做什么 - 让我们有机会了解查询的目的。
描述您的数据集(大小,索引,数据分布)
您的期望是什么?这个查询应该在1秒,1分钟,1小时内完成吗?多久时间?它被召唤多少次(每秒多次或每周一次?)
我认为你的问题被修改是不公平的 - 这是一个有效的问题,但只需要更多的信息。祝你好运。
答案 3 :(得分:1)
我怀疑这最终会成为数据库设计问题,而不是查询优化问题。尽管如此,分析此查询的步骤都已在上面概述。重申:
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侧的数据。这可能不是一个好主意。
答案 4 :(得分:0)
如果不知道表的结构以及表中存在哪些索引或统计信息,则很难对查询性能进行故障排除。正如所建议的那样,您最好的第一步是查看执行计划并确定大部分成本在哪里。常见的解决方法是实现其他索引以减少表扫描。
查询调优在某种程度上是一门艺术,所以很多人都没有就此问题找到一个“正确”的共识。
答案 5 :(得分:0)
正如其他人所说,在不了解所有事实的情况下提供建议很困难。除了其他人给出的建议,如果您经常运行此查询,或者在其他查询中使用某些内部查询,您可能会将它们转换为视图。
答案 6 :(得分:0)
好的代码:-o
正如许多人所说,当我们对数据或您想要实现的目标一无所知时,很难帮助您。
但我可以给你一些指示:
检查http://sql-server-performance.com,了解有关分析和提高查询效果的信息。他们也有一个论坛,但除非你提供更多信息,否则他们也无法帮助你。
WHERE或ON子句中的OR会导致性能下降
你结合以上所有,所以我并不感到惊讶.. 此外,子查询和派生表(您也使用)并不一定会导致性能不佳,但使用错误肯定可以: - )
对于T-SQL的初学者,我建议保持简单。例如,将大查询拆分为您理解的较小查询,使用变量或临时表来保存数据。
许多较小的查询可能会导致比较好的查询更糟糕的性能,但不了解您的代码或为什么它会导致性能不佳会更糟糕:)
祝你好运答案 7 :(得分:0)
我看到了关于缓存的说明。当然可以,只需为结果创建一个表,并将查询结果插入表中。
确保在需要时清除缓存表(例如使用触发器或其他方法)
根据您的系统,使用缓存是一个好的或坏的选择,我不能说。
此外,如果此代码尚未存储在存储过程中,请将其放在一个,因为它使SQL Server更容易缓存计划等。
我建议修复坏代码,而不是用缓存隐藏问题。
欢呼声
/ L