powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Вопрос по использованию индексов в запросе
11 сообщений из 11, страница 1 из 1
Вопрос по использованию индексов в запросе
    #40076946
Sergey Gusev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день.

Помогите, пожалуйста, разобраться в логике использования индексов

1. Есть таблица

Id int
CustomerId int
Name nvarchar(100)
..... (несколько других полей)

2. Есть кластерный PK по Id

3. Есть индекс по CustomerId.

Пробуем два варианта запроса:

1. SELECT * FROM [Table] where CustomerId = 1

Execution plan показывает, что идёт Clastered index scan.

2. SELECT * FROM [Table] where id in (SELECT[Id] FROM [Table] where CustomerId = 233365)

Execution plan показывает, что идут два Index seek (по CustomerId и по PK), потом Nested loops.

Собственно, вопросы

- почему в первом случае не используется индекс по полю?
- станет ли MS Sql его использовать при большом количестве записей?
- нужно ли как-то форсировать использование индекса или всё равно не сделю лучше, чем разработчики Ms SQL и в нужный момент будет автоматически лучший путь выборки?

Заранее спасибо, я больше бэкенд программист, чем SQL эксперт, в таких вещах разбираюсь неважно.
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076955
felix_ff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sergey Gusev
Добрый день.
- почему в первом случае не используется индекс по полю?


потому что вы выбираете все поля (select * ) а таких поле в некластерном индексе нет, поэтому оптимизатор считает что скан кластерного индекса будет дешевле

если перепишите запрос на
Код: sql
1.
SELECT [id] FROM [Table] where CustomerId = 1



получите поиск.


не используйте никогда select * при тестах, выбирайте только те поля которые в действительности вам нужны

Дополню: если строк в таблице мало или по гистограмме видно что предикат не будет особенно селективен оптимизатор все равно может посчитать что скан будет дешевле.

По большей мере оптимизатор строит предположения на основе статистики, держите ее в актуальном состоянии.
Вы всегда можете зафорсировать подсказку, но это требуется в исключительных вариантах.
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076959
msLex
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
felix_ff
Sergey Gusev
Добрый день.
- почему в первом случае не используется индекс по полю?


потому что вы выбираете все поля (select * ) а таких поле в некластерном индексе нет, поэтому оптимизатор считает что скан кластерного индекса будет дешевле

если перепишите запрос на
Код: sql
1.
SELECT [id] FROM [Table] where CustomerId = 1




получите поиск.


не используйте никогда select * при тестах, выбирайте только те поля которые в действительности вам нужны


второй запрос автора вручную реализует механизм key lookup.



Sergey Gusev
- почему в первом случае не используется индекс по полю?

Как уже сказали, ваш индекс не содержит всех нужны для запроса данных, и при его использовании получится ровно тот план, что вы видите во втором случае.

Sergey Gusev
- станет ли MS Sql его использовать при большом количестве записей?

Да

Sergey Gusev
- нужно ли как-то форсировать использование индекса или всё равно не сделю лучше, чем разработчики Ms SQL и в нужный момент будет автоматически лучший путь выборки?

"Зависит от"
Для вашего первого запрос при таких индексах хинт (forceseek) вряд ли навредит.

Код: sql
1.
SELECT [id] FROM  [Table] with(forceseek)  where CustomerId = 1
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076960
Sergey Gusev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
felix_ff

не используйте никогда select * при тестах, выбирайте только те поля которые в действительности вам нужны


Мне как раз нужны все поля в конечном результате. И я сейчас в размышлениях - делать ли самостоятельную выборку сначала id по простому индексу, а потом все поля по кластерному. Или это будет напрасной тратой усилий и оптимизатор запросов MS SQL решит эту проблему за меня.
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076962
felix_ff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sergey Gusev
felix_ff

не используйте никогда select * при тестах, выбирайте только те поля которые в действительности вам нужны


Мне как раз нужны все поля в конечном результате. И я сейчас в размышлениях - делать ли самостоятельную выборку сначала id по простому индексу, а потом все поля по кластерному. Или это будет напрасной тратой усилий и оптимизатор запросов MS SQL решит эту проблему за меня.


тогда вы возможно неудачно выбрали ключ кластеризации.

если нужны все поля делайте или кластерный индекс по [CustomerId]

или модифицируйте свой некластерный индекс что бы он покрывал запрос, (используя INCLUDE список полей которые будут участвовать в конечном селекте)
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076963
Sergey Gusev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
msLex
Для вашего первого запрос при таких индексах хинт (forceseek) вряд ли навредит.


Вот спасибо, добрый человек! Поставил - и прямо всё как хотел - Index seek и Key lookup
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076965
felix_ff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sergey Gusev
msLex
Для вашего первого запрос при таких индексах хинт (forceseek) вряд ли навредит.


Вот спасибо, добрый человек! Поставил - и прямо всё как хотел - Index seek и Key lookup


Любой Key Lookup / RID Lookup относительно дорогая операция, старайтесь как раз их избегать.

На малом объеме возвращаемых данных вы особо не увидите накладных расходов, а когда объемы данных подрастут то вернуть к примеру набор в 100000 строк с использованием Key/RID Lookup уже будет достаточно наглядно видно что показывает оверхед по статистики IO
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076968
Sergey Gusev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
felix_ff
Любой Key Lookup / RID Lookup относительно дорогая операция


А я думал, это даже луче, чем Index Seek.

Получается, мой второй вариант (из стартового сообщения) - оптимальный? Там два Index seek.
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076971
msLex
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sergey Gusev
felix_ff
Любой Key Lookup / RID Lookup относительно дорогая операция


А я думал, это даже луче, чем Index Seek.

Получается, мой второй вариант (из стартового сообщения) - оптимальный? Там два Index seek.

Физически это одно и тоже.

Range Scan (все записи из индекса по заданному CustomerId) - 1 "спуск по дереву"
По каждой из полученных записей поиск в кластерном индексе - N "спусков по дереву"


Надо понимать, что каждый единичный index seek, это random IO, а перебор записей одной за другой - это последовательное чтенье (в том числе в рамках одной страницы) с read ahead вычиткой страниц.

Что будет быстрее в конкретном случае - вопрос.

В SQL Server заложены некие эмпирические оценки этих операций.
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076973
felix_ff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Sergey Gusev
felix_ff
Любой Key Lookup / RID Lookup относительно дорогая операция


А я думал, это даже луче, чем Index Seek.

Получается, мой второй вариант (из стартового сообщения) - оптимальный? Там два Index seek.


Ну держите Вам тест для игры, можете сами поиграться с вариантами выборок.
Можете даже отдельно запустить после наполнения таблиц скоп селектов с выводом актуального плана, он там петухов в процентном соотношении посчитает и покажет что будет более менее наглядно показывать картину.


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
use tempdb;

drop table if exists #tmp1, #tmp2;

create table #tmp1 (
      [id] int index IX clustered,
      [customerID] int index NIX,
      [name] sysname,
      [surname] sysname,
      [patronymic] sysname,
      [comment] nvarchar(4000)
);

create table #tmp2 (
      [id] int,
      [customerID] int index IX clustered,
      [name] sysname,
      [surname] sysname,
      [patronymic] sysname,
      [comment] nvarchar(4000)
);

create table #tmp3 (
      [id] int index IX clustered,
      [customerID] int,
      [name] sysname,
      [surname] sysname,
      [patronymic] sysname,
      [comment] nvarchar(4000)
);
create nonclustered index NIX on #tmp3 ([customerID]) include ([name], [surname], [patronymic], [comment]);



insert into #tmp1
select top (50000)
      row_number() over (order by 1/0),
      1+ cast(CRYPT_GEN_RANDOM(4, 0x25F18060) as bigint) % 10,
      cast(newid() as nvarchar(128)),
      cast(newid() as nvarchar(128)),
      cast(newid() as nvarchar(128)),
      replicate('A', cast(CRYPT_GEN_RANDOM(4) as bigint) % 4000)
from master.dbo.spt_values c1
    cross join master.dbo.spt_values c2;

insert into #tmp2 select * from #tmp1;
insert into #tmp3 select * from #tmp1;


set statistics io, time on;

print '------------------------TEST-----------------------'
print '#tmp1 nonclustered index seek'
select [id] from #tmp1 where [customerID] = 4;
print '---------------------------------------------------'
go
print '#tmp1 nonclustered index seek + keylookup' 
select * from #tmp1 where [customerID] = 4;
print '---------------------------------------------------'
go
print '#tmp1 clustered index seek'
select * from #tmp1 where [id]  < 40;
print '---------------------------------------------------'
go

print '#tmp2 clustered index seek specific column'
select [id] from #tmp2 where [customerID] = 4;
print '---------------------------------------------------'
go
print '#tmp2 clustered index seek all columns' 
select * from #tmp2 where [customerID] = 4;
print '---------------------------------------------------'
go
print '#tmp2 clustered index scan'
select * from #tmp2 where [id]  < 40;
print '---------------------------------------------------'
go

print '#tmp3 nonclustered index seek specific column'
select [id] from #tmp3 where [customerID] = 4;
print '---------------------------------------------------'
go
print '#tmp3 nonclustered index seek all columns' 
select * from #tmp3 where [customerID] = 4;
print '---------------------------------------------------'
go
print '#tmp3 clustered index scan'
select * from #tmp3 where [id]  < 40;
print '---------------------------------------------------'
go




а еще можете поиграться с самой выборкой и к примеру из select *, сделать выборку где не будет выбираться колонка [comment] и циферки начнут изменяться
...
Рейтинг: 0 / 0
Вопрос по использованию индексов в запросе
    #40076978
Sergey Gusev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
felix_ff
Ну держите Вам тест для игры, можете сами поиграться с вариантами выборок.


Спасибо, как раз сейчас сам это сделал. Добавил 4.7 миллионов записей и попробовал запросы из своего первого сообщения.

Первый запрос перестал быть IndexScan, стало IndexSeek + KeyLookup. Второй остался прежним. По скорости практически идентичны.

Спасибо всем, кто отвлёкся на мой вопрос.
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Вопрос по использованию индексов в запросе
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]