C# MSSQL参数消耗更多时间

C# MSSQL参数消耗更多时间,c#,sql,sql-server,performance,C#,Sql,Sql Server,Performance,我有一个数据库,有一个表,有大约2500.000条记录。我获取了大约150000条记录,需要测试两个不同的查询。第一个在30秒到1分钟之间返回结果。但是第二个,在3-4分钟内做出反应,这很奇怪。唯一的变化是第一个不使用参数,但第二个使用参数。我从C运行这两个。对于安全问题,我想使用参数化的一个,但我不明白为什么要花这么多时间。任何帮助都将不胜感激 第一个问题: DECLARE @page INT=3 DECLARE @pagesize INT=300

我有一个数据库,有一个表,有大约2500.000条记录。我获取了大约150000条记录,需要测试两个不同的查询。第一个在30秒到1分钟之间返回结果。但是第二个,在3-4分钟内做出反应,这很奇怪。唯一的变化是第一个不使用参数,但第二个使用参数。我从C运行这两个。对于安全问题,我想使用参数化的一个,但我不明白为什么要花这么多时间。任何帮助都将不胜感激

第一个问题:

        DECLARE @page INT=3
        DECLARE @pagesize INT=300
            string sql = "SELECT  Col1,Col2,Col3 FROM 
    (SELECT ROW_NUMBER() OVER(ORDER BY Col1) AS rownumber,Col1,Col2,Col3";
            sql += " FROM my_table WHERE  Col1 LIKE '" + letter + "%')  as somex 
WHERE  rownumber >= (@page-1)*(@pagesize)";
            sql += "AND rownumber <=(@page)*@pagesize; 
SELECT COUNT(*) FROM my_table WHERE col1 LIKE '" + letter + "%'";
第二个问题:

    DECLARE @page INT=3
    DECLARE @pagesize INT=300
    DECLARE @starting VARCHAR(10)='be'
        string sql = "SELECT  Col1,Col2,Col3FROM   
(SELECT ROW_NUMBER() OVER(ORDER BY Col1) AS rownumber,Col1,Col2,Col3";
        sql += " FROM my_table WHERE  Col1 LIKE @letter+'%')  as somex  
WHERE  rownumber >= (@page-1)*(@pagesize)";
        sql += "AND rownumber <=(@page)*@pagesize; SELECT COUNT(*) 
FROM my_table WHERE col1 LIKE @letter+'%'";
我的服务器是16GB Ram,4个真实的4个虚拟CPU,Sata磁盘

编辑:Col1是聚集索引和非聚集索引


进展:事实证明,这些查询在另一台服务器上运行良好。但这让我更加困惑。这可能是SQL Server的一些设置吗?

正如我在一篇评论中所说的,听起来像是,但出于帮助的目的,我想我会对此进行扩展。网上有很多文章 详细程度要比我详细得多,但参数嗅探的长与短在于SQL Server缓存了一个基于参数值的执行计划,该参数值不会为当前值生成最佳执行计划

假设Col1上有一个非聚集索引,但不包括col2或col3作为非键列,那么 SQL Server有两个选项,它可以在My_表上执行聚集索引扫描以获取Col1所在的所有行,如@letter+'%',或者它可以搜索Col1上的索引,然后在聚集索引上执行书签查找以获取值 对于索引返回的每一行。我记不清SQL Server根据估计的行数在哪一点在这两个点之间切换,这是一个很低的百分比,因此我相当确定如果您返回150000条记录 在2500000中,Optimizer将进行聚集索引扫描。然而,如果您只返回几百行,那么书签查找将是更好的选择

当您不使用参数时,SQL Server将在每次执行时创建一个新的执行计划,并为该参数生成最佳执行计划(假设您的统计信息是最新的),当您在第一次运行参数查询时使用参数时,SQL Server将创建一个计划 基于该特定参数值,并存储该计划以供以后使用。以后每次运行查询时,sql server都会识别查询是相同的,因此不会重新编译它。这意味着,如果第一次运行查询,它是为 返回少量行的参数,然后将存储书签查找计划。然后,如果下一次运行查询时,会传递一个返回大量行的值,其中最佳计划是聚集索引扫描,则仍会使用次优书签查找和 将导致更长的执行时间。当然,反过来也是如此。有很多方法可以绕过参数嗅探,但是由于查询不是很复杂,编译时间不会很长,特别是与您所说的这个查询所花费的30秒相比 要在最佳状态下运行,我将使用“重新编译”选项:


听起来像。除了GarethD,你应该:1-确保col1上有索引2-执行countcol1而不是count*3-更新你的表统计我编辑了问题。col1上既有聚集索引也有非聚集索引。我将count*改为countcol1,但这一点都没有影响。感谢您的回答,并花时间解释:但问题不在于索引。问题是,在C语言中,当我们直接在sql命令中声明参数时,它比使用command.AddWithValue添加参数时工作得更快……你误解了,我没有说索引有问题。使用参数SQL Server正在重用缓存的执行计划时,对于要传递的参数的实际值而言,这可能不是最佳执行计划。如果不使用该参数,SQL Server将无法使用缓存的计划,因为它每次都是一个新查询。这就是为什么您会看到不同之处。在我所做的关于参数嗅探的文章中,我发布了一些查询示例,您可以对这些查询进行测试,并查看同一查询的不同执行计划。即使不使用存储过程,同样的原则也适用。从c调用查询的事实与此无关。
SELECT  Col1, Col2, Col3
FROM    (   SELECT  ROW_NUMBER() OVER(ORDER BY Col1) AS rownumber,Col1,Col2,Col3
            FROM    my_table 
            WHERE   Col1 LIKE @letter+'%'
        )  as somex  
WHERE   rownumber >= (@page-1)*(@pagesize)
AND     rownumber <= (@page) * @pagesize
OPTION (RECOMPILE); 

SELECT  COUNT(*) 
FROM    my_table 
WHERE   Col1 LIKE @letter+'%'
OPTION (RECOMPILE);
SELECT  Col1, Col2, Col3
FROM    My_table
WHERE   Col1 LIKE @letter+'%'
ORDER BY Col1 OFFSET (@page-1) * (@pagesize) ROWS FETCH NEXT @pagesize ROWS ONLY;