#sql-server #indexing #sql-execution-plan
Вопрос:
Я пытаюсь выбрать таблицу с 17 миллионами записей . Это занимает около 10 минут . Здесь вы можете ознакомиться с планом выполнения в реальном времени .
Вот моя структура таблицы :
CREATE TABLE [bas].[GatewayReceipt](
[Id] [INT] IDENTITY(1,1) NOT NULL,
[CustomerId] [INT] NULL,
[UserId] [INT] NOT NULL,
[RefNumber] [NVARCHAR](200) NULL,
[ResNumber] [NVARCHAR](200) NULL,
[Price] [DECIMAL](18, 5) NOT NULL,
[GatewayChannelId] [INT] NOT NULL,
[StatusId] [INT] NOT NULL,
[EntryDate] [DATETIME] NOT NULL,
[ModifyDate] [DATETIME] NULL,
[RowVersion] [TIMESTAMP] NOT NULL,
CONSTRAINT [PK_Bas_GatewayReceipt] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [FG_ATS]
) ON [FG_ATS]
GO
Как примечание, у меня есть 3 некластеризованных индекса на
1:Идентификатор клиента
2:Идентификатор клиента и идентификатор пользователя
3:gatewaychannelId
мой вопрос :
select * from bas.GatewayReceipt where gatewaychannelId in (1,2,3)
почему мой запрос работает медленно ?
Комментарии:
1. И в чем заключается ваш вопрос? ВЫБЕРИТЕ * извне, ГДЕ нельзя использовать индексы
2. @Sergey извините, что я изменил запрос . у меня есть пункт where в gatewaychannelid
3. @Сергей в качестве основного вопроса, почему запрос select без where должен быть таким медленным ?
4. Вы серьезно все, кажется, игнорируете эту вещь. Не имеет значения, есть индекс или нет — даже без индекса сканирование 17 миллионов строк не должно ЗАНИМАТЬ 10 минут на современном оборудовании. Работает ли hit на 5-летнем телефоне, 20-летнем компьютере? ОЧЕНЬ, ОЧЕНЬ, ОЧЕНЬ мало ОПЕРАТИВНОЙ ПАМЯТИ? 10 минут-это возмутительно, индекс это или нет.
5. Что конкретно означает «Это занимает около 10 минут»? Проводите ли вы измерения с точки зрения применения? Насколько медленно приложение извлекает набор результатов и что-то с ним делает? И что это приложение делает с набором результатов? Насколько медленное сетевое соединение между сервером и приложением? Даже если план выполнения может быть улучшен, вы можете не увидеть значительного улучшения, если проблема заключается в потреблении набора результатов.
Ответ №1:
Результаты медленные, в основном из-за времени, необходимого клиентскому приложению (SSMS) для отображения большого результата в 17 миллионов строк.
А именно, SSMS требуется около 70 секунд, чтобы отобразить результат 10 миллионов строк этого запроса на моем компьютере в сетке, и диспетчер задач показывает, что SSMS полностью привязан к процессору во время выполнения:
WITH
t10 AS (SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n))
,t1k AS (SELECT 0 AS n FROM t10 AS a CROSS JOIN t10 AS b CROSS JOIN t10 AS c)
,t10m AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS num FROM t1k AS a CROSS JOIN t1k AS b CROSS JOIN t10 AS c)
SELECT num
FROM t10m;
Повторяя один и тот же запрос без полной визуализации (Запрос—>Параметры—>>Сетка—>>>Удаление результатов после выполнения), для извлечения строк требуется всего 12 секунд, но не для их отображения.
Учтите, что время сквозного ответа является мерой как клиентского, так и серверного времени.
Ответ №2:
С таблицы нужно INDEX
начинать gatewaychannelId
.
Однако, если большинство или все строки в таблице имеют значения 1, 2 или 3, индекс фактически замедлит выполнение запроса. В этом случае быстрее просто прочитать таблицу, отфильтровав несколько строк, которые не применяются.