2010-06-06 3 views
2

Выполнение следующего кода в большой таблице PostgreSQL, объект NpgsqlDataReader блокирует пока все данные не будут извлечены.Как остановить NpgsqlDataReader от блокировки?

NpgsqlCommand cmd = new NpgsqlCommand(strQuery, _conn); 
NpgsqlDataReader reader = cmd.ExecuteReader(); // <-- takes 30 seconds 

Как я могу заставить его вести себя так, чтобы он не предварительно отбирал все данные? Я хочу выполнить набор результатов по строкам, не забрав сразу все 15 ГБ в память.

Я знаю, что были проблемы с такого рода вещами в Npgsql 1.x, но я на 2.0. Это противоречит базе данных PostgreSQL 8.3 на XP/Vista/7. У меня также нет фанки «force Npgsql для предварительной выборки» в моей строке подключения. Я совершенно не понимаю, почему это происходит.

ответ

3

Я удивлен, что драйвер не предоставляет способ сделать это, но вы можете вручную выполнить инструкции SQL, чтобы объявить курсор, открыть его и извлечь из него в пакетах. то есть (и этот код очень сомнительно, как я не C# парень):

new PgsqlCommand("DECLARE cur_data NO SCROLL CURSOR AS " 
       + strQuery, _conn).ExecuteNonQuery(); 
do { 
    NpgsqlDataReader reader = new NpgsqlCommand("FETCH 100 FROM cur_data", _conn) 
              .ExecuteReader(); 
    int rows = 0; 
    // read data from reader, incrementing "rows" for each row 
} while (rows > 0); 
new PgsqlCommand("CLOSE cur_data", _conn).ExecuteNonQuery(); 

Обратите внимание, что:

  • Вы должны быть внутри блока транзакции использовать курсор, если не указан параметр «HOLD» при его объявлении, и в этом случае сервер будет генерировать результаты на серверный временный файл (вам просто не нужно будет передавать его все одновременно)
  • Настройка cursor_tuple_fraction может привести к другому планировать использовать при выполнении запроса с помощью курсора, а не в непосредственном режиме. Вы можете захотеть сделать «SET cursor_tuple_fraction = 1» непосредственно перед объявлением курсора, так как вы на самом деле собираетесь извлечь весь вывод курсора.
+0

Я бы поднял голову, но у меня пока нет репутации. Мой план резервного копирования заключается в том, чтобы объявить курсор вручную, как вы предлагаете. В идеале я хотел бы, чтобы DataReader «просто работал». :) Разве не все дело в DataReader, что это быстрый способ прямого доступа к данным? Поэтому это поведение кажется мне странным. –

+0

@Swingline Rage: возможно, что драйвер .net просто менее зрелый, чем даже драйвер JDBC. Полагаю, что протокол postgresql имеет механизм для получения результатов любого запроса с помощью курсора (команды SQL - это отдельный интерфейс более высокого уровня). Может быть, Npgsql просто не имел поддержки для использования этого написанного? Istr, что традиционный вызов PQexecutequery() на самом деле просто возвращает весь результат за один раз и, по-видимому, пытается оставить это в буфере ОС и обработать его peicemeal будет плохо ... – araqnid

+0

Да, хороший момент (и несколько удручающий). Я рассмотрю это более подробно. Я продолжаю забывать, что Npgsql является открытым исходным кодом, поэтому ответы есть. Но в последний раз, когда я смотрел, я обнаружил, что код трудно следовать, как всегда, с внутренними данными. –

1

Какой тип Npgsql вы используете? Некоторое время назад мы добавили поддержку больших таблиц. Фактически, протокол Postgresql версии 3 поддерживает пейджинг через большие результаты без использования курсоров. К сожалению, мы еще не реализовали его. Простите за это.

Пожалуйста, попробуйте с Npgsql 2.0.9 и сообщите мне, если у вас все еще есть проблемы.

Смежные вопросы