代码之家  ›  专栏  ›  技术社区  ›  massimogentilini

SQL Server 2005和Hibernate使用索引时出现问题

  •  0
  • massimogentilini  · 技术社区  · 16 年前

    我对Hibernate生成的不使用索引的查询有问题。使用JTDS从Java访问数据库,服务器版本为SQL server ,最新的服务包。

    还可以使用带有以下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
    

    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
    

    所需帮助:

    • 如何强制JTDS/Hibernate组合使用索引(SendStringParametersUnicode在默认情况下已设置为false)?
    • 对这种行为有什么解释吗?

    马西莫

    2 回复  |  直到 16 年前
        1
  •  1
  •   garik    16 年前

    该字段的值非常低。我认为在这种情况下,SQLServer将选择扫描然后使用索引(SQLServer自动选择使用或不使用索引本身)。这是有道理的。你应该分析你的想法 或者命令hibernate使用自定义查询请求数据(我认为是可能的),并向查询中添加表提示以强制使用某些索引:

    select PK, DATA, DATANULL from TestNulls WITH INDEX(IDX_DATANULL)
    

    选择性 是“行数”/“基数”,所以如果你有10K的客户,并搜索所有“女性”,你必须考虑到搜索将返回10K/5= 5K行,所以一个非常“坏”的选择性。

    运气。

        2
  •  0
  •   VladV    16 年前

    因此,要使用索引,服务器必须:1)在索引中找到给定的值并检索相应的行ID,2)按ID检索行并返回数据。

    鉴于数据的性质,优化器“认为”完全扫描效率更高。

    我建议你试试:

    1. 重新生成表上的统计信息。过时的统计数据可能会导致优化器做出错误的决策。
    2. 通过添加一些数据来创建这个查询的覆盖索引(它会使插入/更新稍微慢一些,因此您应该考虑对系统的总体影响):

      在TestNulls(DATANULL)INCLUDE(PK,DATA)上创建索引IDX\u DATANULL\u FULL