Похоже, фактический вопрос в том, как быстро вставить записи из большого количества файлов JSON в таблицу SQL Server.
Производительность и взаимоблокировки
Попытка решения медленная, поскольку она пытается вставить записи Row By Agonizing Row (RBAR).Это самый медленный способ сделать это.
Он блокируется, потому что он использует долгоживущие соединения, что означает, что блокировки строк и таблиц накапливаются и удерживаются, пока соединение остается открытым.Если таблица не имеет первичного ключа или некластеризованного индекса, SQL Server, возможно, придется взять больше блокировок на странице данных или даже на уровне таблицы и сохранять их до тех пор, пока соединение остается открытым.
Использование многопоточности в этомдело может усугубить ситуацию, так как несколько соединений ждут друг друга.Если отсутствующие индексы вызывают чрезмерную блокировку, соединения могут в конечном итоге блокировать страницы данных, необходимые друг другу, и, следовательно, взаимоблокировать.
Существует множество способов вставки данных JSON в SQL Server
JSON в SQL Server 2016 и более поздних версиях .
SQL Server 2016 и имеют функции JSON, которые можно использовать для анализа строк JSON.Можно написать хранимую процедуру, которая принимает строку JSON в качестве параметра, анализирует ее с помощью OPENJSON и вставляет значения в таблицу.Кража примера из OPENJSON - Самый простой способ импортировать текст JSON в таблицу :
INSERT INTO Person
SELECT *
FROM OPENJSON(@json)
WITH (id int,
firstName nvarchar(50), lastName nvarchar(50),
isAlive bit, age int,
dateOfBirth datetime2, spouse nvarchar(50))
При отправке всего содержимого файла на SQL Server не будет использоваться more данных, чем отправка отдельных текстовых значений.
OPENROWSET
Другой вариант - загрузить файлы JSON напрямую с помощью OPENROWSET и проанализировать его с помощью OPENJSON, например:
INSERT INTO TargetTable(ID,Name,Price,Pages,Author)
SELECT book.id, book.name, book.price, book.pages_i, book.author
FROM OPENROWSET (BULK 'C:\JSON\Books\books.json', SINGLE_CLOB) as j
CROSS APPLY OPENJSON(BulkColumn)
WITH( id nvarchar(100), name nvarchar(100), price float,
pages_i int, author nvarchar(100)) AS book
Разбор на стороне клиента и SqlBulkCopy
Другой вариант - это анализ текста на стороне клиента, например, с помощью JSON.NET, и массовая вставка данных с использованием SqlBulkCopy.SqlBulkCopy использует те же механизмы, которые использовались BULK INSERT
или bcp
для максимально быстрой вставки данных с минимальным ведением журнала.
FastMember's ObjectReader можно использовать для преобразования списка элементов вIDataReader ожидается SqlBulkCopy.Код может быть примерно таким:
var json=File.ReadAllText(path);
var data=JsonConvert.DeserializeObject<List<SomeType>>(json);
using(var bcp = new SqlBulkCopy(connection))
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description"))
{
bcp.DestinationTableName = "SomeTable";
bcp.WriteToServer(reader);
}
Или, как метод:
void ImportJson<T>(string path,string tableName,string[] fields)
{
var json=File.ReadAllText(path);
var data=JsonConvert.DeserializeObject<List<T>>(json);
using(var bcp = new SqlBulkCopy(connection))
using(var reader = ObjectReader.Create(data, fields))
{
bcp.DestinationTableName = tableName;
bcp.WriteToServer(reader);
}
}
Разбор на стороне клиента и многострочные INSERT
Вместо того, чтобы выполнять отдельные операторы INSERT, производительность может быть улучшена путем их пакетирования или использования многострочных операторов INSERT, например:
INSERT INTO TABLE TableA (Col1,Col2)
VALUES
(Val11,Val12),
(Val21,Val22)
Хотя писать это вручную скучно.Можно использовать другое творение Марка Гравелла, Dapper , чтобы выполнить несколько ВСТАВК:
var json=File.ReadAllText(path);
var data=JsonConvert.DeserializeObject<List<T>>(json);
conn.Execute("INSERT INTO TableA (Col1,Col2) VALUES(@Prop1,@Prop2)",data);
Есть и другие варианты.Данные могут быть отправлены в виде табличного параметра, еще одну вещь, которую проще сделать с Dapper