Может ли SQL Server BULK INSERT считываться из именованного канала/fifo?
Возможно ли для BULK INSERT / bcp читать из именованного канала, FIFO -style?
То есть, вместо чтения из реального текстового файла, можно ли сделать массовую вставку/bcp для чтения из именованного канала, который находится на конце записи другого процесса?
Например:
- создать именованный канал
- распакуйте файл в именованный канал
- чтение из именованного канала с помощью bcp или BULK INSERT
Или:
- создать 4 именованных канала
- разделить 1 файл в 4 потока, записывая каждый поток в отдельный именованный канал
- чтение из 4 именованных каналов в 4 таблицы w / bcp или BULK INSERT
Ближе всего я нашел этого парня (сайт теперь недоступен), который сумел написать в именованную трубу w/ bcp, с его собственной утилитой и использованием так:
start /MIN ZipPipe authors_pipe authors.txt.gz 9
bcp pubs..authors out \.pipeauthors_pipe -T -n
Но он не мог заставить работать обратное.
Поэтому, прежде чем я отправлюсь на дурацкое задание, я задаюсь вопросом, возможно ли вообще читать из именованной трубы с объемной вставкой или bcp. И если бы это было возможно, как бы вы это устроили? Будет ли NamedPipeServerStream
или что-то еще в пространстве имен .NET System.IO.Pipes
адекватным?
Например, пример С помощью Powershell:
[reflection.Assembly]::LoadWithPartialName("system.core")
$pipe = New-Object system.IO.Pipes.NamedPipeServerStream("Bob")
И затем....Что?
4 ответа:
Мне удалось заставить BULK INSERT (но не BCP) корректно работать с именованными каналами в Windows 7 ans SQL Server 2008R2. Есть несколько трюков.
Во-первых, я должен был создатьдва экземпляра именованных каналов на двух разных потоках, оба с одинаковым именем канала. SQL Server откроет первый экземпляр, прочитает из него несколько байт и закроет его, в результате чего WriteFile вызовет исключение PipeException в первом потоке. После этого SQL Server немедленно откроет именованный канал и выполнит входящий поток. все данные из него. Если бы у меня не было второго потока, сидящего в фоновом режиме, готового обслуживать данные, SQL server вернул бы ошибку, прежде чем мой первый поток успел бы восстановиться из исключения PipeException.
Во-вторых, я должен был записать все данные в один вызов WriteFile. Я начал с цикла, в котором я записал несколько пакетов в трубу, но BULK INSERT использовал только первый пакет, который я написал. Это, кажется, делает неблокирующее чтение и рассматривает любое чтение, которое возвращает ноль байт как конец файла. В-третьих, файл формата XML, если он используется, должен быть записан в обычный файл. Мне не удалось заставить SQL Server прочитать файл формата из канала. Я не знаю, Может ли он читать файл формата не XML из канала.
Я бы прокомментировал @DanMenes (спасибо за вдохновение), но для справочных целей я добавляю его как отдельный ответ.
Я разработал решение в .NET, которое открывает канал (на самом деле 2, Сначала он разрушается, как сказал @DanMenes), подготавливает потоковую передачу данных в него, а затем запускает
BULK INSERT
С автоматически сгенерированным файлом формата.Предпосылка заключается в том, что я могу делать такие вещи, как
var inMemoryData = new[] { new[] { "val1", "val2" }, new[] { "val3", "val4" }, }; using (var importer = new Importer(SqlConnection, "MyTable", "Col1", "Col2")) { importer.Import(inMemoryData); }
Я подведу итог реализации импортера:
1. Создавать труба
var stream = new NamedPipeServerStream(name, PipeDirection.Out, 2, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); stream.BeginWaitForConnection(OnConnection, this);
2. Принимать соединения
public void OnConnection(IAsyncResult asyncResult) { Stream.EndWaitForConnection(asyncResult); var buffer = Encoding.UTF8.GetBytes(data); Stream.Write(buffer, 0, buffer.Length); Stream.Close(); }
3. Начать массовую вставку
var insertCommand = DbConnection.CreateCommand(); insertCommand.CommandText = "BULK INSERT [MyTable] FROM '\\.\pipe\mypipe' WITH (FORMATFILE='c:\path\to\formatfile')"; insertCommand.ExecuteNonQuery();
Смотрите проект GitHub для получения более подробной информации.
Примечание: я еще не добавил тесты производительности в проект, но предварительные тесты показали прирост производительности между 2x и 5x по отношению к транзакционному
INSERTs
.
К сожалению, оба адаптера плоских файлов SSIS, BULK INSERT и BCP принимают монопольную блокировку записи на файл (даже если он фактически не записывается в него). Вот почему это не работает.
Я не уверен, что трубы можно настроить так, чтобы разрешить два эксклюзивных замка на одной и той же трубе без серьезного взлома. Вы могли бы обойти его, я полагаю, или взломать fltmgr.sys:)
Как и предлагалось в других плакатах, использование .NET API для выполнения массовых операций или интерфейса OLEDB или ODBC, скорее всего, проще, хотя это означает, что вы должны написать свой собственный анализатор файлов.