В настоящее время я просматриваю способы передачи списков целых чисел в SQL-запросе и пытаюсь решить, какие из них лучше всего в какой ситуации, каковы преимущества каждого из них, и каковы подводные камни, чего следует избегать :)Передача целых списков в sql-запросе, лучшие практики
Сейчас я знаю 3 способа, которыми мы в настоящее время используем в нашем приложении.
1) Таблица значных параметр: Создать новую таблицу оцененная параметр в SQL Server:
CREATE TYPE [dbo].[TVP_INT] AS TABLE(
[ID] [int] NOT NULL
)
Затем выполнить запрос против него:
using (var conn = new SqlConnection(DataContext.GetDefaultConnectionString))
{
var comm = conn.CreateCommand();
comm.CommandType = CommandType.Text;
comm.CommandText = @"
UPDATE DA
SET [tsLastImportAttempt] = CURRENT_TIMESTAMP
FROM [Account] DA
JOIN @values IDs ON DA.ID = IDs.ID";
comm.Parameters.Add(new SqlParameter("values", downloadResults.Select(d => d.ID).ToDataTable()) { TypeName = "TVP_INT" });
conn.Open();
comm.ExecuteScalar();
}
Основными недостатками этого метода заключается в том, что Linq не поддерживает табличные значения params (если вы создаете SP с параметром TVP, linq не сможет его запустить) :(
2) Преобразуйте список в двоичный файл и используйте его в Linq! Это немного лучше .. Создание SP, и вы можете запустить его в LINQ :)
Для этого СП будет иметь параметр IMAGE, и мы будем использовать определенную пользователем функцию (UDF), чтобы преобразовать это в таблицу. В настоящее время у нас есть реализации этой функции, написанные на C++ и в сборке, обе имеют почти такую же производительность :) В принципе, каждое целое число представлено 4 байтами и передается в SP. В .NET есть метод расширения, который CONVERS IEnumerable в массив байт
Метод расширения: общественности статических байт [] ToBinary (это IEnumerable IntList) { возврата ToBinaryEnum (IntList) .ToArray(); }
private static IEnumerable<Byte> ToBinaryEnum(IEnumerable<Int32> intList)
{
IEnumerator<Int32> marker = intList.GetEnumerator();
while (marker.MoveNext())
{
Byte[] result = BitConverter.GetBytes(marker.Current);
Array.Reverse(result);
foreach (byte b in result)
yield return b;
}
}
СП:
CREATE PROCEDURE [Accounts-UpdateImportAttempts]
@values IMAGE
AS
BEGIN
UPDATE DA
SET [tsLastImportAttempt] = CURRENT_TIMESTAMP
FROM [Account] DA
JOIN dbo.udfIntegerArray(@values, 4) IDs ON DA.ID = IDs.Value4
END
И мы можем использовать его, запустив SP непосредственно, или в любой Linq запрос нам нужно
using (var db = new DataContext())
{
db.Accounts_UpdateImportAttempts(downloadResults.Select(d => d.ID).ToBinary());
// or
var accounts = db.Accounts
.Where(a => db.udfIntegerArray(downloadResults.Select(d => d.ID).ToBinary(), 4)
.Select(i => i.Value4)
.Contains(a.ID));
}
Этот метод имеет преимущество используя скомпилированные запросы в linq (который будет иметь такое же определение sql, и план запроса, а также будет кэшироваться) и может также использоваться в SP.
Оба эти методы теоретически неограничен, так что вы можете передать миллионы Интс в то время :)
3) Простой .Contains LINQ() Это более простой подход, и идеально подходит в простой сценарии. Но, конечно, это ограничивается этим.
using (var db = new DataContext())
{
var accounts = db.Accounts
.Where(a => downloadResults.Select(d => d.ID).Contains(a.ID));
}
Самым большим недостатком этого способа является то, что каждое целое число в переменной downloadResults будет передана как отдельный Int .. В этом случае запрос ограничен SQL (максимально допустимый параметров в запросе SQL, который это пара тысяч, если я правильно помню).
Так что я хотел бы спросить ..Как вы думаете, что из этого лучше, и какие другие методы и подходы я пропустил?
Ах да .. Это правда .. Что о производительности? Использует синтаксический анализ xml, создавая большой успех в запросе, exp с большим количеством переданных значений.? –
Когда я использовал это в прошлом. Первое, что я делаю с xml, - это вставить его в индексированную временную таблицу. Затем присоединитесь к этому в основных запросах. Обычно это очень хорошо. –
Поскольку вы единственный, кто ответил здесь, я думаю, что помету ваш ответ как ответ: P Еще раз спасибо за xml tip! –