Ваши результаты выполнения exec sp_spaceused myTable
предоставляют потенциальную подсказку:
rows = 255,000
reserved = 1994320 KB
data = 1911088 KB
index_size = 82752 KB
unused 480KB
Важно отметить, что reserved = 1994320 KB
означает, что ваша таблица составляет около 1866 МБ, когда при чтении полей, которые не проиндексированы (поскольку NVARCHAR(MAX)
не может быть проиндексирован), SQL Server должен прочитать всю строку в память, прежде чем ограничивать колонны. Следовательно, вы легко бежите за пределы 1 ГБ ОЗУ.
В качестве простого теста удалите последние (или первые) строки по 150 тыс. И попробуйте запрос еще раз, чтобы увидеть, какую производительность вы получаете.
Несколько вопросов:
- Имеет ли ваша таблица кластеризованный индекс первичного ключа (это поле
id
или что-то еще)?
- Сортируете ли вы столбец, который не проиндексирован, например поле
`nvarchar(max)
?
В лучшем для вас сценарии ваш ПК равен id
, а также кластеризованному индексу, и у вас либо нет order by
, либо вы order by id
:
Предполагается, что ваше varchar(max)
поле имеет имя comments
:
SELECT id, comments
FROM myTable
ORDER BY id
Это будет работать нормально, но для этого потребуется, чтобы вы прочитали все строки в память (но он будет выполнять только один анализ таблицы), поскольку comments
равен VARCHAR(MAX)
и не может быть проиндексирован, а таблица имеет размер 2 ГБ. SQL будет затем необходимо загрузить таблицу в память по частям.
Скорее всего, у вас что-то вроде этого:
SELECT id, comments
FROM myTable
ORDER BY comment_date
Где comment_date
- дополнительное поле, которое не индексируется. В этом случае поведение будет состоять в том, что SQL не сможет на самом деле отсортировать все строки в памяти, и в конечном итоге придется несколько раз пролистывать таблицу в и из памяти, что может вызвать проблему, с которой вы столкнулись.
Простое решение в этом случае - добавить индекс для comment_date.
Но предположим, что это невозможно, так как у вас есть доступ только для чтения к базе данных, тогда другое решение - создать локальную временную таблицу нужных вам данных, используя следующее:
DECLARE @T TABLE
(
id BIGINT,
comments NVARCHAR(MAX),
comment_date date
)
INSERT INTO @T SELECT id, comments, comment_date FROM myTable
SELECT id, comments
FROM @T
ORDER BY comment_date
Если это не помогает, то требуется дополнительная информация, не могли бы вы опубликовать свой фактический запрос вместе с полным определением таблицы и индексом.
Помимо всего этого, после восстановления резервных копий для восстановления индексов и статистики вы можете выполнить следующее: вы можете просто страдать от испорченной статистики (что происходит, когда вы создаете резервную копию фрагментированной базы данных и затем восстанавливаете ее в новом экземпляре):
EXEC [sp_MSforeachtable] @command1="RAISERROR('UPDATE STATISTICS(''?'') ...',10,1) WITH NOWAIT UPDATE STATISTICS ? "
EXEC [sp_MSforeachtable] @command1="RAISERROR('DBCC DBREINDEX(''?'') ...',10,1) WITH NOWAIT DBCC DBREINDEX('?')"
EXEC [sp_MSforeachtable] @command1="RAISERROR('UPDATE STATISTICS(''?'') ...',10,1) WITH NOWAIT UPDATE STATISTICS ? "