#c# #entity-framework #entity-framework-6
#c# #entity-framework #entity-framework-6
Вопрос:
У меня есть простая сущность, и у меня их 100 000 в моей базе данных SQL Sever 2012:
public class Entity
{
public int Id { get; set; }
public string Field1 { get; set; }
public string Field2 { get; set; }
}
Я хочу показать их в виде сетки, разбитой на страницы, поскольку 100 000 — это слишком много для отображения на одном экране (и не очень эффективно). Сетка должна разрешать сортировку и фильтрацию — очевидно, что все 3 из этих операций лучше всего выполнять на сервере, и EF должен их переводить.
Итак, давайте получим вторую страницу из 500, отсортированную по полю 1:
var items = context.Entities.OrderBy(e => e.Field1).Skip(500).Take(500);
Когда этот запрос выполняется, он занимает 12 секунд! Итак, я покопался в нем и обнаружил, что он переведен следующим образом:
SELECT TOP (500) [Extent1].[Id] AS [Id],
[Extent1].[Field1] AS [Field1],
[Extent1].[Field2] AS [Field2]
FROM (SELECT [Extent1].[Id] AS [Id],
[Extent1].[Field1] AS [Field1],
[Extent1].[Field2] AS [Field2],
row_number() OVER (ORDER BY [Extent1].[Field1] ASC) AS [row_number]
FROM [dbo].[Costs] AS [Extent1]) AS [Extent1]
WHERE [Extent1].[row_number] > 500
ORDER BY [Extent1].[Field1] ASC
Конечно, это сортируется дважды? Я не эксперт по SQL, но подзапрос упорядочивает по полю1 и присваивает этот порядок row_number . Затем мы берем ВЕРХНИЕ 500 row_numbers за 500, чтобы получить до 500 строк для страницы 2. Нам не нужно снова упорядочивать результаты по полю1.
Если я удалю финал ORDER BY [Extent1].[Field1] ASC
, результаты запроса будут одинаковыми, а время выполнения сократится примерно до 150 миллисекунд.
Итак, очевидно, что 150 мс предпочтительнее 12 с — есть ли что-то, что я делаю неправильно? Могу ли я что-нибудь сделать, чтобы это исправить?
Обновить
План запроса одинаков для обоих. Единственное различие во всплывающей подсказке для сортировки — это «Фактическое количество строк», равное 4604 для запроса 12s и 1134 для запроса 150ms. Я бы добавил, что это сгенерированные данные из фиксированного списка из 15 слов (для этого теста) — т.е. Поле 1 содержит 1 из 15 значений, так что по существу существует 15 групп по 6666 строк.
Комментарии:
1. Если бы это не было заказано во второй раз, SQL Server мог бы свободно возвращать вам записи с помощью
row_number
501, 600, 502, 601, 503… даже 12 300 («дайте мне 500 строк, число которыхrow_number
больше 500″), и вы запросили их какOrderBy(e => e.Field1)
.2. То, что вы опубликовали, является типичным запросом подкачки. Любые проблемы, с которыми вы сталкиваетесь, почти наверняка связаны с отсутствием индексации. Запрос ничего не значит без плана его выполнения.
ORDER BY
Строка не означает, что сервер будет выполнять сортировку каждый раз, когда он с ней сталкивается. Сервер проверит наличие существующих индексов и будет использовать их для вычисления рейтинга и выбора строк для возврата. Я ожидаю, что у вас нет правильных индексов в поле подкачки (т.Е. Field1), что заставляет сервер выполнять полное сканирование и упорядочивание таблицы, прежде чем выбирать необходимые строки.3. @ta.speot.is — Я понимаю, о чем ты говоришь. Подзапрос задает row_number в качестве индекса строки, упорядоченной по Field1 . Эмпирически этот запрос возвращается в порядке строк — это просто совпадение, разве это не гарантировано?
4. Я удивлен, что удаление окончательного заказа ПО результатам приводит к увеличению производительности. SQL Server сведет два порядка к одному физическому виду. Даже если бы сортировка выполнялась дважды, почему запрос стал бы в 100 раз медленнее, а не в 2 раза. Это не имеет смысла. Опубликуйте оба плана выполнения в виде изображений.
5. @CharlesMager: если у вас нет предложения order by, тогда нет необходимости заказывать что-либо. Часто бывает так, что вы хотите (как в этом случае), потому что SQL просто сортирует данные, и он не будет прилагать усилий для их сортировки. Иногда, хотя отсутствие order by будет иметь значение. Все зависит от того, как БД хранит данные внутри. И для записи я тоже удивлен, что удаление этой окончательной сортировки является такой проблемой, но не понимаю, почему это может быть.
Ответ №1:
Это связано с ошибкой / особенностью в SQL Server при объединении потоков TOP и Gather. Индекс исправит это, как и отключение параллелизма (глобально, или для этого пользователя, или для запроса). Подсказка заключалась в том, что потоки Gather передавались в базу данных tempdb, что является чрезвычайно редким состоянием. http://web.archive.org/web/20180220120719/http://sqlblog.com:80/blogs/paul_white/archive/2012/05/03/parallel-row-goals-gone-rogue.aspx Это материал 500-го уровня.
Обратите внимание, что вы не можете пропустить финал ORDER BY
, потому что это делает порядок результатов неопределенным.
Ответ №2:
Я думаю, что ваша проблема связана с выполнением порядка в большом и неиндексированном столбце.
Пожалуйста, убедитесь, что вы выполняете индексацию для этого столбца.
В любом случае order by
предложение было бы лучше со nvarchar
значениями not