SQL Server и SqlDataReader — Триллион записей — Память

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

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

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


person BuddyJoe    schedule 04.12.2009    source источник
comment
Вы планируете прочитать триллион записей? или это просто для интереса?   -  person gbn    schedule 05.12.2009


Ответы (3)


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

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

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

person Jon Skeet    schedule 04.12.2009
comment
Итак, мой первоначальный вопрос заключался в том, какова наилучшая стратегия пакетной обработки для ADO.NET и SQL Server... Итак, как лучше всего обрабатывать 1000 записей за раз. Допустим, вы выполняете действие типа MapReduce. Я понимаю, что для этого есть другие инструменты (открытые и коммерческие), но если компания, в которой вы работаете, не позволит вам их использовать... мне от них никакой пользы. (кроме попыток позаимствовать идеи) - person BuddyJoe; 04.12.2009
comment
Хорошая мысль о 12 днях +1. Возможно, я выбрал слишком большое число. - person BuddyJoe; 04.12.2009
comment
Честно говоря, лучшая стратегия пакетной обработки будет зависеть от конкретного характера задачи. Можете ли вы надежно разделить его на пакеты, даже если запросы будут выполняться позже? Можете ли вы заранее разделить его на партии и дать разным компьютерам разные партии? Что-нибудь еще пишет в эти данные? Есть соответствующие индексы? По сути, это случай разработки способа разделения ваших данных в доступной для запросов и эффективной форме. - person Jon Skeet; 04.12.2009
comment
Вот с такими вопросами я и мучился. Люди могут записывать данные, пока я нахожусь в середине процесса. У меня нет хорошей стратегии моментальных снимков. Это то, что я действительно пытаюсь получить мой мозг вокруг. - person BuddyJoe; 04.12.2009
comment
Сначала это может быть один сервер (4 ядра), работающий с данными. Может быть, два или три сервера к концу года. Думаю об использовании F# в этом проекте. Кажется, хорошо подходит для этого. - person BuddyJoe; 04.12.2009

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

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

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

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

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

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

person Remus Rusanu    schedule 04.12.2009
comment
Очень хорошая информация. +1 Какую роль играют транзакции в системе, если данные должны быть только в конечном счете непротиворечивыми? Что бы вы предложили, это правильный способ пакетной обработки 1000 или 10000 за раз? (см. комментарии к Джону Скитту) - person BuddyJoe; 06.12.2009
comment
Правильный способ создания пакетов, которые можно безопасно возобновить, зависит от фактической выполняемой задачи. Тривиальный пример — иметь таблицу с «текущим» кластерным значением ключа. В транзакции вы получаете значение из таблицы, выбираете следующие 10 тыс. строк в порядке кластеризованного ключа, обрабатываете их, обновляете текущее значение ключа в таблице, фиксируете. Промыть, прокрутить и повторить. - person Remus Rusanu; 07.12.2009

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

person Cade Roux    schedule 04.12.2009