【问题标题】:How to compare perfomance of queries via LINQ-to-SQL and plain SQL-Server如何通过 LINQ-to-SQL 和普通 SQL-Server 比较查询的性能
【发布时间】:2014-08-28 10:13:21
【问题描述】:

我想比较 3 种方法的查询执行性能:

  • 查询类型化数据集
  • 使用 LINQ-to-SQL 进行查询
  • 直接在 SQL Server 2008 R2 上执行的 SQL 查询

因此,我想运行一些测试场景,如下所示:

查询类型化数据集

在这里,我使用 Dataset Desinger 创建了数据集。然后我像这样查询相应的 TableAdapter

var minDat = new DateTime(2014, 5, 1);
var maxDat = new DateTime(2014, 5, 2);

var ta = new MyTableAdapter();
vat res = (from row in ta.GetData() 
              where row.Date >= minDat && row.Date <= maxDat
              select row).ToArray();

这会导致超时,因为它将首先从数据库中的表中获取所有数据并在接收到的对象上执行查询。这是意料之中的,很好。

查询类型化数据集

我在 Visual Studio 中使用 O/R-Designer 创建了一个 LINQ-to-SQL 类

var minDat = new DateTime(2014, 5, 1);
var maxDat = new DateTime(2014, 5, 2);

var context = new LtSqlDataContext();

var query = (from row in context.MyTable
                where row.Date >= startTime && row.Date <= endTime
                select row).ToArray;   // I do the .ToArray() to actually receive the whole set of results, i guess here i am doing sth. wrong

这总共需要 2294 毫秒。到目前为止,这似乎是合理的。

SQL 查询

将 LINQ-to-SQL-Query 的执行时间与在 SQL Server Management Studio 中执行的实际 SQL 查询进行比较时,事情变得奇怪了。

declare @min datetime2 = '20140501';
declare @max datetime2 = '20140502';

select * 
    from MyTable 
    where   Date >= @min
        and Date <= @max

这需要 6 秒多一点,准确地说是 6211 毫秒(取自 SQL Server Profiler - Batch Completed)。

这怎么可能?

我想我可能没有正确理解 LINQ-to-SQL 的概念。我认为在查询上调用 ToArray() 会导致实际将查询元组传输到数组中。但是,当直接在服务器上执行时,这会比查询更快(大约 3 倍)吗?

有没有更好的方法来比较这 2 个概念的查询性能?

PS: LINQ-to-SQL 生成的查询与在 SQL Server Mgmt Studio 中执行的查询相同

编辑: LINQ-to-SQL 生成的查询看起来……像下面这样

set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language Deutsch
set dateformat dmy
set datefirst 1
set transaction isolation level read committed

exec sp_executesql N'SELECT [t0].[Column1], [t0].[Column2], [t0].[Column3], [t0].[Column4], [t0].[Column5], [t0].[Date], [t0].[Column7]
FROM [Alle].[MyTable] AS [t0]
WHERE ([t0].[Date] >= @p0) AND ([t0].[Date] <= @p1)',N'@p0 datetime2(7),@p1 datetime2(7)',@p0='2014-05-01 00:00:00',@p1='2014-05-02 00:00:00'

我尝试在 SSMS 中执行它,但仍然需要 6 秒左右....

【问题讨论】:

  • 您是说当您分析 LINQ-to-SQL 和 SSMS SQL 示例时,它们在 Profiler 中看起来相同,除了 SSMS SQL 需要 6 秒而 LINQ-to-SQL 需要 2 秒?
  • 是的。查询的结构相同。虐待发布它作为编辑的问题..
  • 又是这样;您是否尝试过通过 sp_executesql 而不是直接运行“确切的”查询?这可以测量。另外:您需要检查两者的SET 选项;你可以使用@@OPTIONS 来发现这个(more details here
  • 是的,我有。一样的。我也不明白。我会试试这些选项。但我必须先阅读你的链接。
  • 也许ToArray 仍然没有加载数据。也许您应该以某种方式使用该对象来强制它。

标签: c# sql sql-server linq strongly-typed-dataset


【解决方案1】:

可能归结于非常不同的查询构造 - 特别是参数化和使用的日期时间类型。您可以在 SSMS 中比较:

或者您可以在 SSMS 中执行相同的操作,只需:

declare @min datetime = '20140501', @max datetime = '20140502';

exec sp_executesql N'select * 
from MyTable 
where   Date >= @min
and Date <= @max', N'@min datetime, @max datetime', @min, @max;

要在 ADO.NET 中执行与原始查询相同的测试,您将有一个 参数化 查询,并将值作为常规 DateTime 传递,因为这将与其他查询进行比较:

var minDat = new DateTime(2014, 5, 1);
var maxDat = new DateTime(2014, 5, 2);
using(var cmd = conn.CreateCommand()) {
    cmd.CommandText = @"select * 
from MyTable 
where   Date >= @min
    and Date <= @max";
    cmd.Parameters.AddWithValue("min", minDat);
    cmd.Parameters.AddWithValue("max", maxDat);
    using(var reader = cmd.ExecuteReader()) {
        while(reader.Read()) {...}
    }
}

或者更简单地说,使用 dapper 之类的东西:

var minDat = new DateTime(2014, 5, 1);
var maxDat = new DateTime(2014, 5, 2);
var rows = conn.Query<SomeType>(@"select * 
from MyTable 
where   Date >= @min
    and Date <= @max", new { minDat, maxDat }).ToList();

其中SomeType 的属性类似于表中的列。

【讨论】:

  • 感谢您的回答!但我愿意使用与 SSMS 中执行的查询等效的 LINQ 查询。据我所知,这基本上就是我所做的,我只是想知道为什么使用 LINQ-to-SQL 更快?
  • @nozzleman 您发布的 SSMS 查询等同于 LINQ-to-SQL 正在执行的操作;这就是我回答的第一部分的重点。您是否尝试过我答案顶部的 TSQL? 那个表现如何?
  • 它的执行方式与原始 SSMS 查询相同。也许你可以告诉我,为什么 LINQ-to-SQL 更快。这将回答我的问题。如果我在调试时观察生成的 LINQ-to-SQL 语句查询,它与我在 SSMS 中的查询编辑器中键入的查询相同。我只是想知道为什么 LINQ-to-SQL 更快。顺便说一句,感谢您的努力。
  • @nozzleman 剩下的主要选项是SET options;这些可能会有显着的性能变化,并且 SSMS 默认值与 ADO.NET 的不同。您是否在使用任何奇特的东西,例如计算的持久索引列? (他们讨厌 SET 选项)。但是:LINQ-to-SQL 速度更快没有根本原因——我怀疑还有其他差异。而且我仍然很确定 L2S 将使用参数化形式;为了方便起见,我强烈怀疑您所看到的“调试时的 LINQ-to-SQL 语句”是一个善意的谎言;p
【解决方案2】:

返回多少行?

.

返回 565173 行

给你。 SSMS 处理许多行很慢。您的基准无效。从您的应用程序中使用 ADO.NET 执行 LINQ 查询和 SQL 查询。遍历所有行。在 ADO.NET 版本中,检索所有列值以强制反序列化。

现在持续时间可能会非常接近,ADO.NET 会更快。

如果 LINQ to SQL 仍然更快,则可能会出现其他问题,例如缓存计划或 SET 选项错误。不过,对于这样一个简单的查询,我会感到惊讶。

【讨论】:

    猜你喜欢
    • 2020-02-04
    • 2013-01-13
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多