Оптимизированные для памяти таблицы SQL Server - как я могу обеспечить поиск таблиц?
У меня возникли некоторые проблемы при получении поля с одним столбцом "varchar(5)" для надежного использования поиска по таблице вместо сканирования по таблице. Производственная таблица в этом случае содержит 25 миллионов строк. Как бы впечатляюще ни было сканирование 25 миллионов строк за 35 секунд, запрос должен выполняться намного быстрее.
Вот частичное описание таблицы
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) является проблемой. Я, вероятно, попробую преобразовать почтовые индексы в целое число, чтобы посмотреть, что произойдет.
Но я предпочел бы знать, что происходит, чем просто пробовать вещи случайным образом.
2 ответа
Минимизировать размер:
Используйте SmallInt для почтового индекса
Рассмотрим TinyInt для IncomeCode
Используйте #temp для ZipCodesForMO с PK
И объединение
SELECT ...
FROM SummaryTable
JOIN #zipCodesForMOWHERE
on SummaryTable.zipcode = #zipCodesForMOWHERE.ZipCode
Это немного долго для комментария.
Сначала попробуйте переписать как join
:
SELECT st.*
FROM SummaryTable st JOIN
@ZipCodesForMO z
ON st.ixZIP = z.ZipCode;
Причиной этого является то, что JOIN
у них больше возможностей для оптимизации, чем IN
,
Я думаю, что причина, по которой SQL Server предпочитает полное сканирование таблицы, заключается в том, что за каждым поиском по индексу должен следовать поиск по странице, чтобы выбрать остальные столбцы в таблице. Это удваивает объем работы. У вас есть узкие записи, поэтому даже 25 миллионов строк могут уместиться на 30 000 страниц или около того.
Я думаю, что отсечение 64 слишком мало. Но список из 10000 почтовых индексов потребует чтения около 10000 страниц. С поиском по индексу - очень грубым образом - удвоить усилия. Таким образом, сканирование таблицы может иметь разумную или сходную производительность (последовательное сканирование значительно оптимизируется по сравнению со случайным сканированием).