Ваши результаты запуска 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 должен прочитать всю строку в памяти, прежде чем ограничивать столбцы. Следовательно, вы легко бежите за пределом RAM 1 ГБ.
В качестве простого теста удалите последние (или первые) строки 150k и повторите запрос, чтобы узнать, какую производительность вы получите.
Несколько вопросов:
- ли ваша таблица есть кластерный индекс по первичному ключу (это его
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 ? "
Больше тестирования - установлена полная версия SQLServer 2008 R2 на том же компьютере с той же базой данных. DataReader запустил 250 000 записей за 4,3 минуты против 22 минут с помощью SQLExpress. – econner
Вы говорите, что получаете доступ только к символам ~ 1k, но насколько велика фактическая таблица? Запустите 'exec sp_spaceused myTable' (замените' myTable' вашим именем таблицы). Максимальный размер для одной записи «NVARCHAR (MAX)» довольно велик, и поскольку вы не будете/не можете иметь индекс в поле «NVARCHAR», вы будете запрашивать всю строку, поэтому, если есть другой столбец скажем, 10 Кбайт в строке, ваши 250 тыс. строк на самом деле составляют 2,5 ГБ и т. д., что означает, что он не может полностью вписываться в ОЗУ. – Seph
rows = 255,000. зарезервировано = 1994320 КБ, данные = 1911088 КБ, index_size = 82752 КБ, неиспользованный 480 КБ – econner