Добро пожаловать в форум, Guest >> Войти | Регистрация | Поиск | Правила | | В избранное | Подписаться | ||
Все форумы / Microsoft SQL Server |
![]() ![]() |
PizzaPizza Member Откуда: Сообщений: 422 |
Доброго дня есть три таблички 1. 10000 строк CREATE TABLE [Year].[dbo].[import_header]( [id_header] [int] NOT NULL, [code] [nvarchar](10) NOT NULL, [method] [nvarchar](20) NOT NULL, [A_DT] [datetime2](0) NOT NULL, [import_DT] [datetime2](0) NOT NULL, [id_user] [int] NOT NULL, [p_] [nvarchar](20) NULL, [Comment] [nvarchar](max) NULL, [method_type] AS (left([A_method],(3))) ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] с индексом (и еще парой не участвующих) CREATE CLUSTERED INDEX [p_code] ON [dbo].[import_header] ( [p_] ASC ) 2. 400000 строк CREATE TABLE [Year].[dbo].[import_data]( [id_header] [int] NOT NULL, [id_import_fld] [int] NOT NULL, [rt] [decimal](5, 3) NULL, [rt_expected] [decimal](5, 3) NULL, [ar] [int] NULL, [he] [int] NULL ) ON [PRIMARY] с индексом CREATE CLUSTERED INDEX [id_header_import_data] ON [dbo].[import_data] ( [id_header] ASC, [id_import_fld] ASC ) соединены ключем ALTER TABLE [dbo].[import_data] WITH CHECK ADD CONSTRAINT [FK_import_data_import_header] FOREIGN KEY([id_header]) REFERENCES [dbo].[import_header] ([id_header]) 3. 600 строк CREATE TABLE [libra].[dbo].[import_flds]( [id_import_fld] [int] IDENTITY(1,1) NOT NULL, [import_fld] [nvarchar](50) NOT NULL, [method] [nvarchar](50) NOT NULL, [in] [int] NULL, [co] [int] NULL, [s_name] [nvarchar](50) NULL, [mandatory] [int] NULL, [single] [int] NULL, [shift] [decimal](4, 2) NULL ) ON [PRIMARY] CREATE UNIQUE CLUSTERED INDEX [IX_id_import_fld] ON [dbo].[import_flds] ( [id_import_fld] ASC, [import_fld] ASC ) и запрос SELECT [import_header].[code], [import_header].[method], [import_header].[Comment], [import_flds].[s_name], [import_data].[rt], [import_data].[rt_expected], [import_data].[ar], [import_data].[he] FROM [Year].[dbo].[import_header] JOIN [Year].[dbo].[import_data] ON [import_data].[id_header] = [import_header].[id_header] JOIN [libs].[dbo].[import_flds] ON [import_data].[id_import_fld] = [import_flds].[id_import_fld] WHERE [import_header].[p_] = N'092D7G1' AND [import_header].[code] NOT LIKE N'XC%' Две первые таблицы соединяются по ключу [id_header] 1 ко многим. Всего в среднем 83 строки из первой и 32 из второй. Итого ~2500 строк. К этому соединению добавляется третья таблица по ключу [id_import_fld] 1 к 1 просто выборка имени по ключу. И вот тут я не понимаю что происходит. <RunTimeCountersPerThread Thread="0" ActualRows="2984" ActualRowsRead="2984" ActualEndOfScans="2984" ActualExecutions="2984" ActualElapsedms="4" ActualCPUms="4" ActualScans="2984" ActualLogicalReads="5976" ActualPhysicalReads="0" ActualReadAheads="0" ActualLobLogicalReads="0" ActualLobPhysicalReads="0" ActualLobReadAheads="0" /> откуда эти все риды? Помогите прочитать план и понять, что конкретно происходит при этом соединении. План под спойлером
|
|
30 сен 18, 09:01 [21690232] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
Если выделенное жирным, то это количество прочитанных страниц индекса - Индекс читался 2984 раза (ActualScans), каждый раз от корня до листа. Итого читалось 5976 страниц (ActualLogicalReads). |
||
30 сен 18, 10:14 [21690253] Ответить | Цитировать Сообщить модератору |
PizzaPizza Member Откуда: Сообщений: 422 |
Вот это вот чтение 2984 раза всего индекса мне и не нравится. Там всего до 200 уникальных ключей для соединения и я не вижу повода ему на каждую строку первого соединения читать весь индекс из второго соединения. |
||||
30 сен 18, 10:33 [21690256] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
|
||||
30 сен 18, 10:45 [21690260] Ответить | Цитировать Сообщить модератору |
PizzaPizza Member Откуда: Сообщений: 422 |
Вот! В этом то и заключается вопрос :) в чтении плана. Я вижу, что от первого соединения приходит 2984 строк и третья таблица возвращает 2984 строк соответственно. При этом первая таблица даёт ActualLogicalReads="6", вторая ActualLogicalReads="266", а третья сразу ActualLogicalReads="5976". Что у меня с таблицей или индексом на [import_flds] такое, что даёт такую разницу? Или я не понимаю семантику плана и так и должно быть? |
||
30 сен 18, 18:56 [21690487] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
Для поиска значения по ключу необходимо пройти все уровни индекса от корневого до листового. Каждый уровень - логическое чтение страницы. И так 2984 раза, потому что соединение по NL. Полученное ActualLogicalReads="5976" говорит, что в индекесе 2 уровня. |
||
30 сен 18, 19:45 [21690516] Ответить | Цитировать Сообщить модератору |
PizzaPizza Member Откуда: Сообщений: 422 |
invm, Теперь вижу. (Думать - тяжело). У меня есть рандомные ключи в левом соединении и я по каждому из них дёргаю индекс правой таблицы. Каждый ключ отдельно и для двух уровней по две страницы чтения. Тогда я полагаю, что из первой и второй таблиц у меня выборки идут блоками подряд, поэтому страниц меньше выбирается, тк кластер. Спасибо. Теперь стройнее картина. Вот думаю не лучше было бы прочитать весь индекс из третей таблицы и сделать left join мерджем или хашем. А то получается если у меня в левом соединении из 2984 строк уникальных ключей только 200, то ему надо делать все равно 2984 отдельных чтений, вместо того, что бы выбрать весь индекс (600 строк). Попробую сегодня с хинтами. |
30 сен 18, 20:17 [21690535] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31813 |
Физически, конечно, индекс читается один раз, и не весь, а используемые страницы (точнее, для оптимизации читаются блоки по 8 страниц). Но поисков нужно 2984 * 2, что и отражается в плане. |
||
30 сен 18, 21:29 [21690577] Ответить | Цитировать Сообщить модератору |
PizzaPizza Member Откуда: Сообщений: 422 |
invm, Обновил статистику и теперь у меня hash match и одно выполнение index scan на второе соединение без всяких хинтов. Просто чудо какое то. Единственное, что не понятно теперь, это из-за трейса 2371 который я включил на моем 2014 экспрессе или просто само обновление статистики помогло. |
30 сен 18, 21:33 [21690581] Ответить | Цитировать Сообщить модератору |
PizzaPizza Member Откуда: Сообщений: 422 |
Ну если бы тут было бы физических 2984 чтений, то вопросы у меня были бы другие. :) Вот этот момент с поисками он не очевиден, его надо осмыслить, что когда на loop приходят не сортированные по ключу соединения данные, то loop делает индивидуальные поиски на каждую строку первого кортежа. |
||||
30 сен 18, 21:58 [21690589] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9683 |
|
||
30 сен 18, 22:01 [21690591] Ответить | Цитировать Сообщить модератору |
PizzaPizza Member Откуда: Сообщений: 422 |
invm, Видимо мне надо посмотреть на трейс флаги для анализа статистики, а то сейчас я ориентируюсь только на разницу между актуальным выполнением и эстимейтом. |
30 сен 18, 23:55 [21690643] Ответить | Цитировать Сообщить модератору |
Все форумы / Microsoft SQL Server | ![]() |