[英]SQL Server query suddenly slow
I have a problem with a SQL database query that suddenly (but regularly about every three weeks) becomes slow. 我有一个SQL数据库查询的问题突然 (但通常大约每三周)变得缓慢。
Setup is the following: 安装程序如下:
Orders
) the query is mainly selecting from has around 24000 records, five other joined tables are small (100 records or less) Orders
)主要是从大约24000条记录中选择的,其他5条连接表都很小(100条记录以下) Orders
has a varbinary(MAX)
column Report
that contains binary data (PDF documents) with an average size of about 200 to 300 kB (but can be up to 2 MB occasionally). Orders
有一个varbinary(MAX)
列Report
,其中包含平均大小约为200到300 kB的二进制数据(PDF文档)(偶尔可以高达2 MB)。 More than 90% of those 24000 orders have this column filled, for the others it is NULL
, ie more than 90% of the 6 GB database size are binary data. NULL
,即6 GB数据库大小的90%以上是二进制数据。 The query in question has the following structure: 有问题的查询具有以下结构:
SELECT TOP (30) [Project2].[OrderID] AS [OrderID]
-- around 20 columns more
FROM ( SELECT [Project2].[OrderID] AS [OrderID],
-- around 20 columns more
row_number() OVER (ORDER BY [Project2].[OrderID] ASC) AS [row_number]
FROM ( SELECT [Filter1].[OrderID] AS [OrderID]
-- around 20 columns more
FROM ( SELECT [Extent1].[OrderID] AS [OrderID]
-- around 20 columns more
FROM [dbo].[Orders] AS [Extent1]
INNER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
WHERE ([Extent1].[Status] IS NOT NULL)
AND (4 = CAST( [Extent1].[Status] AS int))
AND ([Extent1].[SomeDateTime] IS NULL)
AND ([Extent1].[Report] IS NULL)
) AS [Filter1]
OUTER APPLY (SELECT TOP (1) [Project1].[C1] AS [C1]
FROM ( SELECT CAST( [Extent7].[CreationDateTime] AS datetime2) AS [C1],
[Extent7].[CreationDateTime] AS [CreationDateTime]
FROM [dbo].[OtherTable] AS [Extent7]
WHERE [Filter1].[OrderID] = [Extent7].[OrderID]
) AS [Project1]
ORDER BY [Project1].[CreationDateTime] DESC
) AS [Limit1]
) AS [Project2]
) AS [Project2]
WHERE [Project2].[row_number] > 0
ORDER BY [Project2].[OrderID] ASC
It is generated from a LINQ-to-Entities query by Entity Framework. 它是由Entity Framework从LINQ到实体查询生成的。 The query occurs in a few variations which are only different in the first
WHERE
clause: 查询发生在一些变体中,这些变体仅在第一个
WHERE
子句中有所不同:
The five variants 五个变种
WHERE ([Extent1].[Status] IS NOT NULL) AND (X = CAST( [Extent1].[Status] AS int))
X can be between 0
and 4
. X可以在
0
到4
之间。 These queries are never a problem. 这些查询从来都不是问题。
And the two variants (*) 这两个变种(*)
WHERE ([Extent1].[Status] IS NOT NULL) AND (4 = CAST( [Extent1].[Status] AS int)) AND ([Extent1].[SomeDateTime] IS NULL) AND ([Extent1].[Report] IS NULL)
or ... IS NOT NULL...
in the last line. 或者
... IS NOT NULL...
在最后一行。 I have the problem described below only with those two queries. 我只有这两个查询才会遇到下面描述的问题。
The "phenomenon" is: “现象”是:
An additional observation: 另外一个观察:
Somehow I suspect the whole problem has to do with the memory limitation (1 GB) of the Express edition and the varbinary(MAX)
column although I just use it in the WHERE
clause that checks if the column value is NULL
or not NULL
. 不知怎的,我怀疑整个问题与Express版本和
varbinary(MAX)
列的内存限制(1 GB)有关,尽管我只是在WHERE
子句中使用它来检查列值是NULL
还是非NULL
。 The Report
column itself is not one of the selected columns. “
Report
列本身不是所选列之一。
Since I am running against the limitations (10 GB mdf file size) of the Express edition next year latest I am considering changes anyway: 由于我正在运行明年Express版本的限制(10 GB mdf文件大小),我正在考虑更改:
Orders
table Orders
表中 Question: What could be the reason that the query is suddenly slow? 问题:查询突然变慢的原因是什么? Could one of the changes I am planning solve the problem or are there other solutions?
我计划的其中一项变更可以解决问题还是有其他解决方案?
Edit 编辑
Following bhamby's tip in the comments below I've set SET STATISTICS TIME ON
in SSMS before running the query again. 在下面的评论中按照bhamby的提示,我在SSMS中设置了
SET STATISTICS TIME ON
,然后再次运行查询。 When the query is slow again I get a high value for SQL Server parse and compile time
, namely: CPU time = 27,3 sec
and Elapsed time = 81,9 sec
. 当查询再次变慢时,我得到
SQL Server parse and compile time
的高值,即: CPU time = 27,3 sec
, Elapsed time = 81,9 sec
。 The execution time for the query is only CPU time = 0,06 sec and Elapsed time = 2,8 sec. 查询的执行时间仅为CPU时间= 0,06秒,经过时间= 2,8秒。 Running the query a second time after that gives CPU time 0,06 sec and Elapsed time = 0,08 for the SQL Server parse and compile time.
在此之后第二次运行查询,为SQL Server解析和编译时间提供CPU时间0,06秒和经过时间= 0,08。
This just seems wasteful 这看起来很浪费
SELECT TOP (1) [Project1].[C1] AS [C1]
FROM ( SELECT CAST( [Extent7].[CreationDateTime] AS datetime2) AS [C1],
[Extent7].[CreationDateTime] AS [CreationDateTime]
FROM [dbo].[OtherTable] AS [Extent7]
WHERE [Filter1].[OrderID] = [Extent7].[OrderID]
) AS [Project1]
ORDER BY [Project1].[CreationDateTime] DESC
is 是
SELECT max( CAST( [Extent7].[CreationDateTime] AS datetime2) ) AS [C1]
FROM [dbo].[OtherTable] AS [Extent7]
WHERE [Filter1].[OrderID] = [Extent7].[OrderID]
Why are you not storing dates as datetime? 为什么不将日期存储为日期时间?
I don't like that outer apply 我不喜欢那种外在的申请
I would create a #temp that is run once and join to it 我会创建一个运行一次的#temp并加入它
Make sure and declare [OrderID] as PK 确保并将[OrderID]声明为PK
SELECT [Extent7].[OrderID], max( CAST( [Extent7].[CreationDateTime] AS datetime2) ) AS [C1]
FROM [dbo].[OtherTable] AS [Extent7]
GROUP BY [Extent7].[OrderID]
You could have loop join going on 你可以进行循环连接
Next I would put this in #temp2 so that you are sure it is only run once 接下来我会把它放在#temp2中,这样你就可以确定它只运行一次
Again be sure to declare OrderID as a PK 再次确保将OrderID声明为PK
SELECT [Extent1].[OrderID] AS [OrderID]
-- around 20 columns more
FROM [dbo].[Orders] AS [Extent1]
INNER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
WHERE ([Extent1].[Status] IS NOT NULL)
AND (4 = CAST( [Extent1].[Status] AS int))
AND ([Extent1].[SomeDateTime] IS NULL)
AND ([Extent1].[Report] IS NULL)
If Order is only 24,000 rows then something stupid is going on for you to have queries more than a few seconds. 如果订单只有24,000行,那么你会有一些愚蠢的事情让你查询超过几秒钟。
If it is a query which is run often, then I would suggest turning it into a Stored Procedure and using the results of the procedure. 如果它是经常运行的查询,那么我建议将其转换为存储过程并使用该过程的结果。
In Entity Framework you should be able to import the procedure as a Function Import . 在Entity Framework中,您应该能够将过程作为函数导入导入 。
You can then take control of the Stored Procedure's execution plan by giving it query hints or combating Parameter Sniffing . 然后,您可以通过提供查询提示或对抗参数嗅探来控制存储过程的执行计划。
It smells like your server's execution plans are going out-of-date every 3 weeks, hence the slow-down. 它闻起来像你的服务器的执行计划每3周过时,因此放慢速度。
Also, you mentioned that you are using 64bit SQL. 另外,您提到您使用的是64位SQL。 My experience has been that 64bit SQL does not tend to perform very efficiently with sub-queries.
我的经验是64位SQL在子查询中不能很有效地执行。 My advice would be to try and avoid them.
我的建议是尽量避免它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.