sql-server - sp_executesql 不使用索引?

标签 sql-server nhibernate count

我在我的 Web 应用程序中使用 nHibnerate,但在生成的 sp_execute 中使用索引时遇到问题。我的表有 2.1 亿条记录,查询非常慢。

首先,生成的列“kolumna1”类型存在问题。在数据库中,我有一列 varchar,但 nHibernate 生成了 nvarchar。我通过在强制使用 varchar 的代码中放置特殊属性来解决这个问题。在那个技巧之后 sp_executed 开始使用索引并且一切都是正确的。现在问题又回来了,sp_executesql 需要 10 分钟才能完成。当我检查正常查询(没有 sp_executesql)时,它只用了 1 秒。我检查了两者的执行计划:sp_executesql 没有使用索引,而普通查询使用的是索引。在不更改索引的情况下,我将 varchar 修改回 nvarchar 并且 sp_execute 在 1 秒内完成(使用索引)。任何人都知道我在哪里犯了错误吗?为什么如此小的变化执行计划不同?以及如何解决?

这里我附加了更多代码。以防万一有人需要它。

sp_executesql 与 varchar(8000)

exec  sp_executesql N'SELECT count(*) as y0_  FROM tabela1 this_ WHERE ((this_.kolumna2 >= @p0 and this_.kolumna2 <= @p1)) and  
    (this_.kolumna3 in (@p2, @p3) and this_.kolumna1 like @p4)',N'@p0 datetime,@p1 datetime,@p2 int,@p3 int,@p4 varchar(8000)',
    @p0='2013-01-08 14:38:00' ,@p1='2013-02-08 14:38:00',@p2=341,@p3=342,@p4='%501096109%'

sp_executesql with varchar

sp_executesql with nvarchar(4000)

exec  sp_executesql N'SELECT count(*) as y0_  FROM tabela1 this_ WHERE ((this_.kolumna2 >= @p0 and this_.kolumna2 <= @p1)) and  
    (this_.kolumna3 in (@p2, @p3) and this_.kolumna1 like @p4)',N'@p0 datetime,@p1 datetime,@p2 int,@p3 int,@p4 nvarchar(4000)',
    @p0='2013-01-08 14:38:00' ,@p1='2013-02-08 14:38:00',@p2=341,@p3=342,@p4='%501096109%'

sp_executesql with nvarchar

有趣的是,在 sql profiler 中,两个查询都给出相同的结果:

exec sp_executesql N'SELECT count(*) as y0_ FROM tabela1 this_  
WHERE this_.kolumna3 in (@p2, @p3) and ((this_.kolumna2 >= @p0 and this_.kolumna2 <= @p1))  
and ( this_.kolumna1 like @p4)',N'@p0 datetime,@p1 datetime,@p2 int,@p3 int,@p4 varchar(8000)',  
@p0='2013-01-08 14:38:00' ,@p1='2013-02-08 14:38:00',@p2=341,@p3=342,@p4='%501096109%'  
--Declare @p0 datetime  
--set @p0 = '2013-01-08 14:38:00'  
--Declare @p1 datetime  
--set @p1 = '2013-02-08 14:38:00'  
--Declare @p2 int  
--set @p2 = 341  
--Declare @p3 int  
--set @p3 = 342  
--Declare @p4 varchar(8000)  
--set @p4 = '%501096109%'  
--SELECT count(*) as y0_  
 --FROM tabela1 this_  
 --WHERE ((this_.kolumna2 >= @p0 and  
 --this_.kolumna2 <= @p1)) and  
 --(this_.kolumna3 in (@p2, @p3) and this_.kolumna1 like @p4)

索引如下:

CREATE TABLE [dbo].[tabela1](
[id] [bigint] NOT NULL,
[kolumna1] [varchar](128) NOT NULL,
[kolumna2] [datetime] NOT NULL,
[kolumna3] [int] NOT NULL,
CONSTRAINT [PK__tabela1__4F7CD00D] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [ind_tabela1_ kolumna2] ON [dbo].[tabela1] 
(
    [kolumna2] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [ind_ tabela1_ kolumna3] ON [dbo].[ tabela1] 
(
    [kolumna3] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna1] ON [dbo].[ tabela1] 
(
    [kolumna1] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna2_ kolumna3] ON [dbo].[ tabela1] 
(
    [kolumna2] ASC,
    [kolumna3] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna3_ kolumna2_id_ kolumna1] ON [dbo].[ tabela1] 
(
    [kolumna3] ASC,
    [kolumna2] ASC,
    [id] ASC,
    [kolumna1] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

下面的查询执行计划:select count(*) from [dbo].[tabela1] where [kolumna1] like N'%501096109%' execution plan for query

最佳答案

在以下情况下,SQL Server 查询优化器可以选择使用索引查找:

  1. 除了 LIKE 之外,还有另一个过滤谓词。它应该是一个精确的搜索或者至少是 SARGable 谓词
  2. 表非常大(数百万行)

但是当使用显式类型转换时无法进行查找操作 - 不同的排序规则/数据类型。 您无法控制此行为的另一件事是,查询计划可能因不同的谓词集而异。为此,您需要使用提示 FORCESEEK(版本 2008+)。您可以在这里找到信息: http://msdn.microsoft.com/en-us/library/ms187373%28v=sql.100%29.aspx

关于sql-server - sp_executesql 不使用索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14987495/

相关文章:

java - 如何统计Java应用运行时哪个类被使用了多少次

c# - 使用 NHibernate 映射时无法覆盖类

sql - 替换函数 - 在 SQL SERVER 2008 中处理单引号和正斜杠

sql-server - 签名激活过程中的不可信安全上下文

SQL查询其中列值是唯一的并且不包含

c# - 使用 NHibernate 重用线程的 session

sql-server - NHibernate 加入子类

mysql - 如何使用 MySQL 根据第一个表中特定列中的值从 2 个表中获取记录数

mysql - 从不同的表中计算产品和价格总和

sql-server - 尝试在 SQL 中为购物篮创建存储过程