SQL предназначен для работы с огромными наборами данных и является чрезвычайно мощным. При использовании логики на основе множеств часто нет необходимости перебирать данные для выполнения операций, и существует ряд встроенных способов сделать это в самом SQL.
1) запись на основе логики для обновления данных без курсоров
2) использовать детерминированные пользовательские функции с установленной логикой (это можно сделать с помощью атрибута SqlFunction в коде CLR ). Недетерминированный будет иметь эффект превращения запроса в курсор внутри, это означает, что вывод значения не всегда одинаков при заданном входе.
[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static int algorithm(int value1, int value2)
{
int value3 = ... ;
return value3;
}
3) использовать курсоры в качестве крайней меры. Это мощный способ выполнения логики для каждой строки в базе данных, но он влияет на производительность. Как следует из этой статьи CLR может выполнять SQL-курсоры (спасибо Мартину).
Я видел ваш комментарий о том, что сложность использования логики на основе множеств слишком велика. Можете ли вы привести пример? Существует множество способов SQL для решения сложных задач - CTE, Views, разбиение и т. Д.
Конечно, вы вполне можете быть правы в своем подходе, и я не знаю, что вы пытаетесь сделать, но моя интуиция говорит об использовании инструментов SQL. Создание нескольких читателей не является правильным подходом к реализации базы данных. Вполне может быть, что вам нужно несколько потоков, вызывающих SP, чтобы запустить параллельную обработку, но не делайте этого внутри CLR.
Чтобы ответить на ваш вопрос, с реализациями CLR (и IDataReader
) вам на самом деле не нужно распечатывать результаты по частям, потому что вы не загружаете данные в память или не переносите данные по сети. IDataReader
дает вам доступ к потоку данных построчно. Судя по звукам, ваш алгоритм определяет количество записей, которые необходимо обновить, поэтому, когда это произойдет, просто прекратите звонить Read()
и закончите в этой точке.
SqlMetaData[] columns = new SqlMetaData[3];
columns[0] = new SqlMetaData("Value1", SqlDbType.Int);
columns[1] = new SqlMetaData("Value2", SqlDbType.Int);
columns[2] = new SqlMetaData("Value3", SqlDbType.Int);
SqlDataRecord record = new SqlDataRecord(columns);
SqlContext.Pipe.SendResultsStart(record);
SqlDataReader reader = comm.ExecuteReader();
bool flag = true;
while (reader.Read() && flag)
{
int value1 = Convert.ToInt32(reader[0]);
int value2 = Convert.ToInt32(reader[1]);
// some algorithm
int newValue = ...;
reader.SetInt32(3, newValue);
SqlContext.Pipe.SendResultsRow(record);
// keep going?
flag = newValue < 100;
}