带/不带参数的性能问题

Xav*_*nou 4 sql t-sql sql-server performance

我有一些性能问题.

我有一张大约200万行的表.

CREATE TABLE [dbo].[M8](
    [M8_ID] [int] IDENTITY(1,1) NOT NULL,
    [APPLIC] [char](8) NOT NULL,
    [NIVALERTE] [numeric](1, 0) NOT NULL,
    [LOGDH] [datetime2](7) NULL,
    [USERX] [char](20) NOT NULL,
    [TACHE] [char](3) NOT NULL,
    [PRG] [char](32) NOT NULL,
    [DOS] [numeric](3, 0) NOT NULL,
    [ERRNUM] [numeric](5, 0) NOT NULL,
    [LOGTXT] [char](200) NOT NULL)
Run Code Online (Sandbox Code Playgroud)

我用C#和ADO.NET阅读它们

在管理工作室(SQL Server 2008 R2)中,使用该查询:

SELECT 
    M8.M8_ID, M8.APPLIC, M8.NIVALERTE, M8.LOGDH, M8.USERX, M8.TACHE, 
    M8.PRG, M8.DOS, M8.ERRNUM, M8.LOGTXT
FROM 
    M8 AS M8 WITH(NOLOCK) 
WHERE 
    ((M8.APPLIC LIKE 'DAV' ) )
ORDER BY 
    M8.LOGDH DESC, M8.M8_ID ASC
OPTION (FAST 1)
Run Code Online (Sandbox Code Playgroud)

拥有第一行大约需要1分钟.

但是,随着

DECLARE @APPLIC_ZOOMAPRESCLE_ZOOM_LIKE_APPLIC_WHERE_0 as char(8) = 'DAV'

SELECT 
   M8.M8_ID, M8.APPLIC, M8.NIVALERTE, M8.LOGDH, M8.USERX, M8.TACHE, 
   M8.PRG, M8.DOS, M8.ERRNUM, M8.LOGTXT
FROM 
   M8 AS M8 WITH(NOLOCK) 
WHERE 
   ((M8.APPLIC LIKE @APPLIC_ZOOMAPRESCLE_ZOOM_LIKE_APPLIC_WHERE_0 ) )
ORDER BY 
   M8.LOGDH DESC, M8.M8_ID ASC
OPTION(FAST 1)
Run Code Online (Sandbox Code Playgroud)

我在4秒后得到第一行.

PS:我知道,我没有%.

编辑:以下是执行计划https://www.dropbox.com/sh/jgai5f9txbs84x6/EP5_hj8DNv

Mar*_*ith 5

你的桌子有1,517,820行.其中近三分之一(476,672)包含该值DAV(或者更准确地说DAV?????CHAR(8)数据类型的值,因此用尾随空格填充.

LIKE比较中,尾随空格match_expression并不重要(尽管它们pattern本身很重要).

因此,表达式WHERE APPLIC LIKE 'DAV'确实匹配476,672行.然而,这两个执行计划都没有估计到这附近.虽然更快的计划(带变量)更接近三个数量级.

+-----------------------+-----------+-----------+
|                       | Slow Plan | Fast Plan |
+-----------------------+-----------+-----------+
| Estimated # Rows      | 32        | 47,343    |
| Memory Grant          | 1 MB      | 333 MB    |
| Degree of Parallelism | 1         | 4         |
+-----------------------+-----------+-----------+
Run Code Online (Sandbox Code Playgroud)

对于带有变量的计划,因为SQL Server没有进行变量嗅探(没有例如OPTION (RECOMPILE)提示),它会回到关于有多少行与谓词匹配的猜测,并得出估计约有3.1%的表符合条件.

快速计划

快速

具有字面值的计划应该有更好的估计.您提供的DBCC SHOW_STATISTICS输出屏幕截图(在添加了另外一百万行之后)显示DAV肯定在那里

统计

不幸的是,尽管列值中的尾随空格对于查询结果并不重要,但它们的存在确实搞乱了基数估计(在此处报告为错误并且当前声明在下一版本中已修复).由于这个问题,它估计只返回少量行,并提出以下计划.

慢计划

慢

由于基数估计不佳而导致执行50万次密钥查找,因此内存授权可能不足以满足正在排序的数据大小导致溢出tempdb.

如果可以更改查询或表模式,则可以考虑许多解决方法.

  • 使用=而不是LIKE
  • WHERE子句更改为LIKE CAST('DAV' AS CHAR(8))
  • 将列数据类型更改为VARCHAR(8)(并确保修剪所有存储的值).
  • 删除当前正在寻找的索引(Index_A).您尚未提供其定义,但如果它是具有少量不同值的列上的单列索引,则其存在可能更多是障碍而不是帮助(取决于您的查询工作负载))
  • 使用键列添加覆盖索引APPLIC(可能LOGDH DESC, M8_ID ASC避免排序),将其他引用的列添加为INCLUDED.