Я никогда этого не пробовал - поэтому не знаю, столкнусь ли я с проблемами с памятью.

Но может ли SqlDataReader прочитать триллион записей? Это все транслируется правильно? Я немного не уверен в том, что протокол SQL / TDS делает под прикрытием.

ОБНОВЛЕНИЕ Переведите триллион в очень большое число. Мне, наверное, следовало сказать что-то вроде 1 или 100 миллионов.

7
BuddyJoe 4 Дек 2009 в 22:31
5
Вы планируете прочитать триллион записей? или это просто для интереса?
 – 
gbn
5 Дек 2009 в 12:49

3 ответа

Лучший ответ

Да, это будет стрим ... но я не думаю, что вам действительно стоит пытаться это сделать.

Если бы вы могли читать миллион записей в секунду (что для меня маловероятно), вам все равно потребовалось бы 12 дней, чтобы прочитать триллион записей ... это большая работа, чтобы рискнуть потерять на полпути.

Теперь я понимаю, что вы, вероятно, на самом деле не хотите читать триллион записей буквально, но я хочу сказать, что если вы все равно можете разделить свой "большой объем" работы на логические пакеты, это, вероятно, хороший идея.

11
Jon Skeet 4 Дек 2009 в 22:35
Итак, мой первоначальный вопрос должен был заключаться в том, какова наилучшая стратегия пакетной обработки для ADO.NET и SQL Server ... так каков наилучший способ обрабатывать 1000 записей за раз. Допустим, вы выполняете действие типа MapReduce. Я понимаю, что для этого есть и другие инструменты (открытый и коммерческий), но если компания, в которой вы работаете, не позволит вам их использовать ... они не принесут мне пользы. (кроме попыток позаимствовать идеи)
 – 
BuddyJoe
4 Дек 2009 в 22:49
Хороший отзыв о 12 днях +1. Может, я выбрал слишком большое число.
 – 
BuddyJoe
4 Дек 2009 в 22:50
Честно говоря, лучшая стратегия дозирования будет зависеть от точного характера задачи. Можете ли вы надежно разделить его на партии, даже если запросы будут выполняться позже? Можете ли вы заранее разделить его на партии и дать разным компьютерам разные партии? Что-нибудь еще записывает в эти данные? Есть ли соответствующие индексы? По сути, это случай разработки способа разделения ваших данных в удобной и эффективной форме.
 – 
Jon Skeet
4 Дек 2009 в 22:56
Так что именно с такими вопросами я боролся. Люди могут писать в данные, пока я нахожусь в середине процесса. У меня нет хорошей стратегии «моментального снимка». Это тот, который я действительно пытаюсь понять.
 – 
BuddyJoe
4 Дек 2009 в 23:01
Сначала это может быть один сервер (4 ядра), работающий с данными. Может быть, два-три сервера к концу года. Подумываю об использовании какого-нибудь F # в этом проекте. Кажется, хорошо для этого подходит.
 – 
BuddyJoe
4 Дек 2009 в 23:03

Есть несколько деталей.

  • SqlDataReader обычно читает всю строку в памяти и кэширует ее. Сюда входят любые поля BLOB, поэтому вы можете в конечном итоге кэшировать несколько полей размером 2 ГБ в памяти (XML, VARBINARY (MAX), VARCHAR (MAX), NVARCHAR (MAX)). Если такие поля вызывают беспокойство, вы должны передать CommandBehavior.SequentialAccess на ExecuteReader и использовать возможности потоковой передачи конкретного SqlClient такие типы, как SqlBytes.Stream.

  • Соединение занято, пока не завершится SqlDataReader. Это создает транзакционные проблемы, потому что вы не сможете выполнять какую-либо обработку в базе данных в той же транзакции, потому что соединение занято. Попытка открыть другое соединение и зарегистрироваться в той же транзакции не удастся, так как распределенные транзакции с обратной связью запрещены. Желательно использовать MARS. Для этого нужно установить MultipleActiveResultSets=True о подключении. Это позволяет вам запускать команду в том же соединении, когда средство чтения данных все еще активно (типичный цикл fetch-process-fetch). Внимательно прочтите ссылку на Christian Kleinerman's, убедитесь, что вы понимаете проблемы и ограничения, связанные с MARS и транзакциями, они довольно тонкие и нелогичные.

  • Длительная обработка на клиенте заблокирует сервер. Ваш запрос по-прежнему будет выполняться все это время, и серверу придется приостановить его, когда канал связи заполнится. Запрос потребляет worker (или больше, если у него есть параллельные планы) и рабочие процессы - это очень дефицитный товар на сервере (они примерно приравниваются к потокам). Вы не будете лишены возможности позволить себе множество клиентов, обрабатывающих огромные наборы результатов в свое свободное время.

  • Размер транзакции. Обработка триллиона записей за одну транзакцию никогда не сработает. Журнал должен будет увеличиваться, чтобы вместить всю транзакцию, без усечения и повторного использования VLF, что приведет к огромному росту журнала.

  • Время восстановления. Если обработка 999-миллиардной записи завершится неудачно, ей придется откатить всю проделанную работу, поэтому на откат уйдет еще «12» дней.

14
Remus Rusanu 4 Дек 2009 в 23:17
1
Очень хорошая информация. +1 Какую роль играют транзакции в системе, если данные должны быть согласованы только в конечном итоге? Что вы посоветуете правильному способу пакетной обработки 1000 или 10000 за раз? (см. комментарии к Джону Скиту)
 – 
BuddyJoe
6 Дек 2009 в 22:25
1
Правильный способ создания пакетов, которые можно безопасно возобновить, зависит от фактически выполняемой задачи. Тривиальный пример - таблица с «текущим» значением кластеризованного ключа. В транзакции вы получаете значение из таблицы, выбираете следующие 10 тыс. Строк в порядке кластеризованного ключа, обрабатываете их, обновляете текущее значение ключа в таблице, фиксируете. Промыть, цикл и повторить.
 – 
Remus Rusanu
7 Дек 2009 в 22:04

Да - это может занять некоторое время (если ваш SQL не делает ничего глупого, пытаясь сделать снимок или что-то еще), но если ваш сервер может передавать его в потоковом режиме, у SqlDataReader не должно быть проблем с использованием памяти.

1
Cade Roux 4 Дек 2009 в 22:37