Самый быстрый способ получить счет из таблицы с условиями? - PullRequest
0 голосов
/ 26 октября 2019

Я использую sql server 2017 и EF Core 2.2. В одной из моих таблиц сейчас содержится 5 миллионов записей.

Я хочу сгруппировать все эти записи по "CategoryId", а затем иметь счетчик для каждой.

Мне также нужно отфильтроватьс предложением where.

Однако даже если я напишу запрос на языке Sql, мне все равно потребуется около минуты, чтобы получить эти цифры.

Это слишком медленно, и мне нужно что-то быстрее.

select CategoryId, count(*) from Items where Deleted = 'False'
group by CategoryId

Я предполагаю, что ядро ​​EF, вероятно, не будет иметь решения, которое будет достаточно быстрым, поэтому я открыт для использованияado.net при необходимости. Мне просто нужно что-то быстрое.

Ответы [ 3 ]

1 голос
/ 26 октября 2019

Рассмотрите возможность создания индексированного представления для материализации агрегации:

CREATE VIEW dbo.ItemCategory
WITH SCHEMABINDING
AS
SELECT CategoryId, COUNT_BIG(*) AS CountBig
FROM dbo.Items
WHERE Deleted = 'False'
GROUP BY CategoryId;
GO

CREATE UNIQUE CLUSTERED INDEX cdx_ItemCategory
    ON dbo.ItemCategory (CategoryId);
GO

Использование этого представления для агрегированного результата значительно улучшит производительность:

SELECT CategoryId, CountBig
FROM dbo.ItemCategory;

В зависимости отв вашей редакции SQL Server может потребоваться указать подсказку NOEXPAND для используемого индекса представления:

SELECT CategoryId, CountBig
FROM dbo.ItemCategory WITH (NOEXPAND);
0 голосов
/ 26 октября 2019

У вас должен быть покрывающий индекс для вашего запроса, чтобы он выполнялся быстро, кроме этого, здесь нет ярлыка для повышения производительности, так как ваш запрос должен будет прочитать каждую страницу таблицы для подсчета идентификатора категории.

У меня есть таблица с 5 миллионами строк. Почти 4,7 миллиона строк имеют значение Delete = False, без индекса покрытия мой запрос занимает около 12 секунд, и план выполнения выглядит следующим образом.

enter image description here

Как только я создаю следующий покрывающий индекс для моей таблицы, запрос выполняется менее чем за секунду, и план выполнения выглядит точно так же, но онвыполняет поиск по некластерному индексу, а не сканирует кластерный индекс:

Index Definition:
CREATE NONCLUSTERED INDEX [Test_Index]
ON [dbo].[Test] ([IsDeleted])
INCLUDE ([CategoryId])

enter image description here

При таком покрытии индекс SQL Server будет тольконужно смотреть в индекс и возвращать результаты, а не просматривать всю таблицу.

Если вы действительно хотите ускорить этот запрос, есть еще один очень специфический способ ускорить этот запрос, создав отфильтрованный индекс специально для вашего запроса;

Index definition would be:
CREATE NONCLUSTERED INDEX [Test_Index2]
ON [dbo].[Test] ([CategoryId])
WHERE IsDeleted = 'False'

С помощью этого отфильтрованного индексамой запрос был довольно мгновенным, я не установил время ввода-вывода для моего запроса, но я бы увидел несколько миллисекунд. План выполнения слегка изменился с этим индексом.

enter image description here

0 голосов
/ 26 октября 2019

Вам лучше добавить индексы на "удаленные" и categoryid. Или поместите все удаленные элементы в отдельную таблицу

...