我对 Hibernate 生成的不使用索引的查询有疑问。使用 JTDS 从 Java 访问数据库,服务器版本是 SQL Server 2005,最新的服务包。
该字段可以为空,并且是一个外键,在某些特定情况下,可能完全为空,列通过非聚集索引建立索引,但当列完全为空时从不使用索引,从而创建大量全表扫描和性能问题。
也可以使用带有以下 SQL 代码的标准查询分析器来验证这种情况:
创建表和索引
CREATE TABLE [dbo].[TestNulls](
[PK] [varchar](36) NOT NULL,
[DATA] [varchar](36) NULL,
[DATANULL] [varchar](36) NULL,
CONSTRAINT [PK_TestNulls] PRIMARY KEY NONCLUSTERED
(
[PK] 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 [IDX_DATA] ON [dbo].[TestNulls]
(
[DATA] 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 [IDX_DATANULL] ON [dbo].[TestNulls]
(
[DATANULL] 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
使用 newid 函数填充一些随机数据
declare @i as int
set @i = 0
while (@i < 500000)
begin
set nocount on
insert into TestNulls values(NEWID(), NEWID(), null)
insert into TestNulls values(NEWID(), null, null)
insert into TestNulls values(NEWID(), null, null)
set @i = (@i + 1)
set nocount on
end;
此查询执行全表扫描
declare @p varchar(36)
set @p = NEWID()
select PK, DATA, DATANULL from TestNulls
where DATANULL = @p
如果我使用“and DATANULL IS NOT NULL”完成查询,则查询现在使用索引。
需要帮助:
- 如何强制 JTDS/Hibernate 组合使用索引(默认情况下 sendStringParametersAsUnicode 已设置为 false)?
- 有没有办法为所有使用可空字段的休眠查询附加“并且列不为空”?
- 关于这种行为的任何解释?
问候马西莫