【发布时间】:2012-08-09 03:21:25
【问题描述】:
我有一个 MVC 网站,它提供来自 SQL Server 数据库的数据记录的分页列表。 UI 允许用户根据许多不同的标准过滤返回的数据,例如电子邮件地址。这是一段sn-p代码:
Stopwatch stopwatch = new Stopwatch();
var temp = SubscriberDB
.GetSubscribers(model.Filter, model.PagingInfo);
// Inspect SQL expression here
stopwatch.Start();
model.Subscribers = temp.ToList();
stopwatch.Stop(); // 9 seconds plus compared to < 1 second in Query Analyzer
运行此代码时,秒表显示的执行时间约为 9 秒。如果我捕获生成的 SQL 表达式(就在使用 .ToList() 方法对其进行评估之前)并将其作为查询剪切到 SQL Server Management Studio 中,则执行时间会降至不到 1 秒。这里是生成的 SQL 表达式供参考:
SELECT [t2].[SubscriberId], [t2].[Email], [t3].[Reference] AS [DataSet], [t4].[Reference] AS [DataSource], [t2].[Created]
FROM (
SELECT [t1].[SubscriberId], [t1].[SubscriberDataSetId], [t1].[SubscriberDataSourceId], [t1].[Email], [t1].[Created], [t1].[ROW_NUMBER]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[Email], [t0].[SubscriberDataSetId]) AS [ROW_NUMBER], [t0].[SubscriberId], [t0].[SubscriberDataSetId], [t0].[SubscriberDataSourceId], [t0].[Email], [t0].[Created]
FROM [dbo].[inbox_Subscriber] AS [t0]
WHERE [t0].[Email] LIKE '%_EMAIL_ADDRESS_%'
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN 0 + 1 AND 0 + 20
) AS [t2]
INNER JOIN [dbo].[inbox_SubscriberDataSet] AS [t3] ON [t3].[SubscriberDataSetId] = [t2].[SubscriberDataSetId]
INNER JOIN [dbo].[inbox_SubscriberDataSource] AS [t4] ON [t4].[SubscriberDataSourceId] = [t2].[SubscriberDataSourceId]
ORDER BY [t2].[ROW_NUMBER]
如果我删除电子邮件过滤器子句,那么控制器的 StopWatch 会返回与 SQL Management Studio 查询类似的响应时间,不到 1 秒 - 所以我假设 SQL 管道的基本接口工作正常并且问题在于对 Linq 表达式的评估。我还应该提到,这是一个相当大的数据库,订阅者表中有超过 100 万行。
谁能解释一下为什么会有如此高 (x10) 的性能差异以及有什么办法可以解决这个问题?
【问题讨论】:
-
造成这种情况的常见原因是:参数嗅探和不同的 SET 选项(ansi_nulls,...)。尝试搜索它们。
-
如果您正在运行 SQL Server 的非 Express 版本,请启动 SQL Profiler 并查看这是否是唯一正在处理的查询。它还可能让您更深入地了解时间花在哪里。
-
@Neilski - 你能展示你的 GetSubscribers 方法吗?
-
很难显示 GetSubscribers 的所有代码,因为它非常冗长。它实际上做了什么,它基于过滤器模型中设置的参数构建了一个表达式树。不屑一顾,我不确定它是否相关,因为 a) 最终结果是上面显示的 SQL 表达式,b) 其他过滤条件的性能符合预期,即相当快。
-
我尝试在 Linq Profiler 下运行该应用程序 - 它没有显示任何意外,即 SQL 表达式与上面显示的相同。
标签: asp.net-mvc performance linq-to-sql