0

我在让单列“varchar(5)”字段可靠地使用表搜索而不是表扫描时遇到了一些麻烦。本例中的生产表包含 2500 万行。尽管在 35 秒内扫描 2500 万行令人印象深刻,但查询应该运行得更快。

这是部分表格说明

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 NOT NULL)是否存在某种问题。我可能会尝试将邮政编码转换为整数,看看会发生什么。

但我宁愿知道发生了什么,也不愿简单地随机尝试。

4

2 回答 2

0

最小化大小:
将 SmallInt 用于邮政编码
考虑将 TinyInt 用于收入代码

使用带有 PK
和连接 的 ZipCodesForMO 的#temp

SELECT ...
FROM SummaryTable
JOIN #zipCodesForMOWHERE 
     on SummaryTable.zipcode = #zipCodesForMOWHERE.ZipCode 
于 2015-09-20T07:29:07.030 回答
0

这是一个有点长的评论。

首先,尝试重写为join

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

这样做的原因是JOINs 比 有更多的优化机会IN

我认为 SQL Server 更喜欢全表扫描的原因是因为每次索引查找都需要在页面查找之后进行页面查找以获取表中的其余列。这使工作量增加了一倍。您的记录很窄,因此即使 2500 万行也可能适合 30k 左右的页面。

我认为 64 的截止值太小了。但是 10,000 个邮政编码的列表需要阅读大约 10,000 页左右。使用索引查找,将以非常粗略的方式 - 加倍努力。因此,对表的扫描可能具有相似或更好的性能(顺序扫描比随机扫描显着优化)。

于 2015-09-20T04:37:42.290 回答