У меня есть таблица CustPassMaster
с 16 столбцами, один из которых CustNum varchar(8)
, и я создал индекс IX_dbo_CustPassMaster_CustNum
. Когда я запускаю свое SELECT
заявление:
SELECT * FROM dbo.CustPassMaster WHERE CustNum = '12345678'
Он полностью игнорирует индекс. Это смущает меня, так как у меня есть еще одна таблица CustDataMaster
с большим количеством столбцов (55), один из которых - CustNum varchar(8)
. Я создал индекс для этой колонки ( IX_dbo_CustDataMaster_CustNum
) в этой таблице и использую практически тот же запрос:
SELECT * FROM dbo.CustDataMaster WHERE CustNum = '12345678'
И он использует индекс, который я создал.
Есть ли какие-то конкретные причины этого? Зачем использовать индекс от CustDataMaster
, а не от CustPassMaster
? Это из-за низкого количества столбцов?
Первый запрос возвращает 66 строк. Для второго возвращается 1 строка.
Кроме того, дополнительное примечание: CustPassMaster
имеет 4991 записей и CustDataMaster
имеет 5376 записей. Может ли это быть причиной игнорирования индекса? CustPassMaster
также имеет дубликаты записей, которые имеют одинаковые CustNum
значения. Это еще один фактор?
Я основываю эту претензию на фактических результатах плана выполнения обоих запросов.
Вот DDL для CustPassMaster
(с неиспользованным индексом):
CREATE TABLE dbo.CustPassMaster(
[CustNum] [varchar](8) NOT NULL,
[Username] [char](15) NOT NULL,
[Password] [char](15) NOT NULL,
/* more columns here */
[VBTerminator] [varchar](1) NOT NULL
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_dbo_CustPassMaster_CustNum] ON dbo.CustPassMaster
(
[CustNum] ASC
) WITH (PAD_INDEX = OFF
, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF
, DROP_EXISTING = OFF
, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
И DDL для CustDataMaster
(я опустил много несущественных полей):
CREATE TABLE dbo.CustDataMaster(
[CustNum] [varchar](8) NOT NULL,
/* more columns here */
[VBTerminator] [varchar](1) NOT NULL
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_dbo_CustDataMaster_CustNum] ON dbo.CustDataMaster
(
[CustNum] ASC
)WITH (PAD_INDEX = OFF
, STATISTICS_NORECOMPUTE = OFF
, SORT_IN_TEMPDB = OFF
, DROP_EXISTING = OFF
, ONLINE = OFF
, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
У меня нет кластеризованного индекса ни в одной из этих таблиц, только один некластеризованный индекс.
Не обращайте внимания на тот факт, что типы данных не полностью соответствуют типу хранимых данных. Эти поля являются резервной копией из базы данных IBM AS / 400 DB2, и это совместимые типы данных для нее. (Я должен иметь возможность запрашивать эту резервную копию базы данных с точно такими же запросами и получать точно такие же результаты.)
Эти данные используются только для SELECT
заявлений. Я не делаю никаких INSERT
/ UPDATE
/ DELETE
утверждений на нем, за исключением случаев, когда приложение резервного копирования копирует данные из AS / 400.
источник
Ответы:
Обычно индексы будут использоваться SQL Server, если он сочтет более целесообразным использовать индекс, чем непосредственно использовать базовую таблицу.
Казалось бы, оптимизатор, основанный на затратах, считает, что использование рассматриваемого индекса будет более дорогим. Вы можете увидеть, как он использует индекс, если вместо этого
SELECT *
вы простоSELECT T1Col1
.Когда вы
SELECT *
говорите SQL Server вернуть все столбцы в таблице. Чтобы вернуть эти столбцы, SQL Server должен прочитать страницы строк, соответствующихWHERE
критериям оператора, из самой таблицы (кластеризованный индекс или куча). SQL Server, вероятно, считает, что количество операций чтения, необходимых для получения остальных столбцов из таблицы, означает, что он может также сканировать таблицу напрямую. Было бы полезно увидеть фактический запрос и фактический план выполнения, используемый запросом.источник
INCLUDE
предложение индекса?INCLUDE
предложению, вероятно, заставит SQL Server использовать индекс. Сказав это, что вы пытаетесь оптимизировать? Мне кажется, если ваша таблица имеет средний размер строки в 100 байт, то 5000 строк - это всего лишь около 500 КБ данных, и на них, возможно, не стоит тратить время.Table1
, и 0,53 КБ дляTable2
. Все эти данные импортируются из AS / 400 (IBM System i), и ни на одном ПК нет никаких PK. Сегодня я вручную создал все индексы после того, как люди упоминали, что приложение иногда работает довольно медленно.Для использования индекса, поскольку вы это делаете
select *
, SQL Server должен сначала прочитать каждую из строк индекса, которые соответствуют значению, которое вы указали в предложении where. Исходя из этого, он будет получать значения кластеризованного индекса для каждой строки, а затем он должен искать каждое из них отдельно от кластеризованного индекса (= поиск ключа). Поскольку вы сказали, что значения не являются уникальными, SQL Server использует статистику, чтобы оценить, сколько раз ему приходится выполнять поиск ключа.Скорее всего, оценка затрат на сканирование поисков некластеризованного индекса + ключа превышает оценку затрат на сканирование кластерного индекса, и поэтому индекс игнорируется.
Вы можете попытаться использовать,
set statistics io on
а затем использовать подсказку индекса, чтобы увидеть, действительно ли меньше стоимость ввода-вывода при использовании индекса или нет. Если разница велика, вы можете посмотреть статистику, если она устарела.Кроме того, если ваш SQL на самом деле использует переменные, а не точные значения, это также может быть вызвано анализом параметров (= предыдущее значение, использованное для создания плана, содержало много строк в таблице).
источник
Это может быть причиной. Оптимизаторы основаны на стоимости и решают, какой путь выбрать, основываясь на «стоимости», которую имеет каждый путь выполнения. Самая большая стоимость - это передача данных с диска в память. Если оптимизатор подсчитает, что для чтения индекса и данных требуется больше времени, он может решить пропустить индекс. Чем больше строк, тем больше дисковых блоков они занимают.
источник