Вопрос по sql-server-2008, .net, table-variable, stored-procedures – Табличный параметр: отправка данных небольшими порциями

0

Я читаю из CSV-файла и отправляю данные в виде табличной переменной в хранимую процедуру. Из того, что я тестировал до сих пор, я могу обрабатывать 300 тыс. Записей за 3 минуты 30 секунд. Файл может содержать до миллионов записей на ходу. Я хотел бы знать, если это хорошая идея, чтобы отправить все эти записи в хранимую процедуру за один раз, или я должен отправить их в пакетах, скажем, 500 КБ? Я установил тайм-аут команды на 1800.

Да, вы правы, я использую TVP для отправки данных в хранимую процедуру. user1110790
@AaronBertrand Если вы ссылаетесь на это, это были Вставить значения.stackoverflow.com/questions/8635818/… paparazzo
Вы имеете в виду табличную переменную или табличный параметр? Aaron Bertrand
Я использую TVP для загрузки данных, не думаю, что вам нужно разбивать их. Если вы проследите это - кажется, обрабатываете по одному. Как вы реализуете? Используете ли вы класс, который реализует IEnumerable & lt; SqlDataRecord & gt ;? Я обнаружил, что быстрее DataTable и меньше памяти. paparazzo
Я думал, что @MartinSmith опубликовал некоторую информацию о пороговых значениях для оптимального количества строк, которые нужно передать в TVP, но мне сейчас трудно найти его сообщение. Aaron Bertrand

Ваш Ответ

1   ответ
1


Это работает как обратный читатель данных

Заметьте, я сортирую. Это по кластерному индексу. Фрагментация индексов абсолютно убьет скорость загрузки. Первая реализация использовала Insert Values (несортированные), и за 12 часов работы эта версия буквально в 100 раз быстрее. Я также отключаю индексы, кроме PK и переиндексации в конце загрузки. В конце концов я получаю около 500 строк / секунду. Ваш образец 1400 в секунду, так здорово. Если вы начинаете видеть деградацию, то на что посмотреть.

public class DocFTSinXsCollection : List<DocFTSinX>, IEnumerable<SqlDataRecord>
{
    // used by TVP for fast insert
    private int sID;
    private IEnumerable<DocFTSinX> docFTSinXs;
    IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
    {
        //todo fix the order in 3 to sID, wordID1, workID2
        var sdr = new SqlDataRecord(
        new SqlMetaData("wordID1", System.Data.SqlDbType.Int),
        new SqlMetaData("wordID2", System.Data.SqlDbType.Int),
        new SqlMetaData("sID", System.Data.SqlDbType.Int),
        new SqlMetaData("Delta", System.Data.SqlDbType.Int));
        foreach (DocFTSinX oh in docFTSinXs.OrderBy(x => x.Word1).ThenBy(x => x.Word2))
        {
            sdr.SetInt32(0, oh.Word1);
            sdr.SetInt32(1, oh.Word2);
            sdr.SetInt32(2, sID);
            sdr.SetInt32(3, (Int32)oh.Delta);
            yield return sdr;
        }
    }

    public DocFTSinXsCollection(int SID, IEnumerable<DocFTSinX> DocFTSinXs)
    {
        sID = SID;
        docFTSinXs = DocFTSinXs;
        //Debug.WriteLine("DocFTSinXsCollection DocFTSinXs " + DocFTSinXs.Count().ToString());
    }
}

Другими инструментами, которые следует рассмотреть, являются класс SQLBulkCopy .NET и Drapper.

ОП спросил, как выполнять партиями.

 while (true)
 {
     // if no more break;
     // fill list or datatable with next 100000
     // send list or datatable to db
 }
Ой, спасибо. Позвольте мне попробовать это. user1110790
Смотрите обновление в конце вопроса. Запрос не правильный срок. Это вставка. Реализация TVP будет отправлять вставку по одной записи за раз, независимо от размера пакета. Вы уже заявили, что видели это в профилировщике SQL.
Вы видели обновление в конце вопроса?
Спасибо, Блам, я действительно проверил это, и это было очень эффективно. Но администратор БД и руководство хотят, чтобы я отправлял 100 тыс. Записей за запрос. Вы знаете, как мы можем справиться с этим? Я имею в виду отправку 100K запросов в таблицу данных или как? user1110790
да, @ Blam Спасибо, что поправили меня. Я новичок в этом и ценю вашу помощь. Таким образом, вопрос будет в C #, есть ли способ, которым я могу отправить вставки 100k в TVP? user1110790

Похожие вопросы