2015-09-20 54 views
0

我一直有一些麻烦,获得单列“varchar(5)”字段可靠地使用表查找,而不是表扫描。这种情况下的生产表包含2500万行。如同在35秒内扫描2500万行一样令人印象深刻,查询应该运行得更快。内存优化的SQL Server表 - 如何确保表查找?

这里的一个局部表的描述

CREATE TABLE [dbo].[Summaries_MO] 
(
    [SummaryId] [int] IDENTITY(1,1) NOT NULL, 
    [zipcode] [char](5) COLLATE Latin1_General_100_BIN2 NOT NULL, 
    [Golf] [bit] NULL, 
    [Homeowner] [bit] NULL, 
    [IncomeCode] [char](1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, 
    [Pets] [bit] NULL, 

CONSTRAINT [Summaries_MO_primaryKey] PRIMARY KEY NONCLUSTERED HASH 
(
    [SummaryId] 
)WITH (BUCKET_COUNT = 33554432), 
INDEX [ixZIP] NONCLUSTERED 
(
    [zipcode] ASC 
) 
)WITH (MEMORY_OPTIMIZED = ON , DURABILITY = SCHEMA_AND_DATA) 

典型地,该表与包括一个查询访问:

SELECT ... 
      FROM SummaryTable 

      WHERE ixZIP IN (SELECT ZipCode FROM @ZipCodesForMO) 

此查询坚持使用表扫描。我试过WITH(FORCESEEK)例如,但这只是使查询失败。

正如我已经研究了这个问题,我也试过:

SELECT * FROM Summaries WHERE ZipCode IN ('xxxxx', 'xxxxx', 'xxxxx') 

当我运行此查询有64个或更少(实际的,有效的)邮政编码,查询使用表查找。

但是,当我给它65或更多的邮政编码它使用表扫描。

总之,生产查询总是使用表扫描,当我指定65个或更多的邮政编码时,查询也使用表扫描。

坦率地说,我想知道索引列(Latin1_General_100_BIN2不为NULL)的数据类型是否有问题。我可能会尝试将邮政编码转换为整数以查看会发生什么。

但我宁愿知道发生了什么,而只是随意尝试。

回答

0

这是有点长的评论。

首先,尝试改写为join

SELECT st.* 
FROM SummaryTable st JOIN 
    @ZipCodesForMO z 
    ON st.ixZIP = z.ZipCode; 

之所以这样做是JOIN■找优化比IN更多的机会。

我认为SQL Server更喜欢全表扫描的原因是因为每个索引seek都需要跟一个页面查找来获取表中其余的列。这使工作量增加了一倍。你有狭窄的记录,所以即使2500万行可能适合3万页左右的页面。

我认为64的临界值太小。但是,一个10000个邮政编码的清单需要阅读大约10,000个左右的页面。通过索引查找,会 - 以非常粗略的方式 - 将努力加倍。因此,对表格进行扫描可能会有相似或更好的性能(顺序扫描会比随机扫描显着优化)。

0

最小尺寸:
使用SMALLINT的邮政编码
考虑TINYINT为IncomeCode

使用#TEMP为ZipCodesForMO与PK
而联接

SELECT ... 
FROM SummaryTable 
JOIN #zipCodesForMOWHERE 
    on SummaryTable.zipcode = #zipCodesForMOWHERE.ZipCode