在没有事务的情况下执行批量插入的性能令人困惑

时间:2019-07-15 11:54:37

标签: c# postgresql xunit

我正在使用临时表批量插入数百万条记录,以两种方式检查性能-有无事务。首先,删除是否存在并在每次测试之前创建新表。

//Filling up data to insert, calling from constructor
    private void FillData()
    {
        _insertData = new List<TransactionDto>();

        for (var i = 1; i <= 1000000; i++)
        {
            _insertData.Add(new TransactionDto(i, $"Insert{i}"));
        }
    }

    private void PrepareDbTables(NpgsqlConnection connection)
    {
        var query = @"DROP TABLE IF EXISTS TransactionTest;
                      CREATE TABLE TransactionTest(id integer,text varchar(24))";
        connection.Query(query);
    }
    private void DropAndCreateTempTable(NpgsqlConnection connection)
    {
        var query = @"DROP TABLE IF EXISTS TmpTransactions";
        connection.Execute(query);
        query = @"CREATE TEMP TABLE TmpTransactions (id integer, text varchar(24));";
        connection.Execute(query);
    }

这是2个测试:

    [Fact]
    public void CheckInsertBulkSpeedWithOutTransaction()
    {
        var sw = new Stopwatch();
        using (var con = new NpgsqlConnection(ConnectionString))
        {
            con.Open();           
            //Delete and create new table TransactionTest
            PrepareDbTables(con);
            DropAndCreateTempTable(con);
            sw.Start();

            InsertBulkWithTempTable(null, _insertData, con);
            sw.Stop();
        }

        _output.WriteLine(
            $"Test completed. InsertBulk without transaction {_insertData.Count}  elements for: {sw.ElapsedMilliseconds} ms");
    }

与交易相同的测试:

    [Fact]
    public void CheckInsertBulkSpeedWithTransaction()
    {
        var sw = new Stopwatch();
        using (var con = new NpgsqlConnection(ConnectionString))
        {
            con.Open();
            //Delete and create new table TransactionTest
            PrepareDbTables(con);

            DropAndCreateTempTable(con);
            sw.Start();

            using (var transaction = con.BeginTransaction(IsolationLevel.ReadUncommitted))
            {
                InsertBulkWithTempTable(transaction, _insertData, con);
                transaction.Commit();
                transaction.Dispose();
            }
            sw.Stop();

        }

        _output.WriteLine(
            $"Test completed. InsertBulk with transaction {_insertData.Count}  elements for: {sw.ElapsedMilliseconds} ms");
    }

插入对象记录的主要方法:

private void InsertBulkWithTempTable(NpgsqlTransaction transaction, List<TransactionDto> data, NpgsqlConnection connection)
    {
            using (var writer =
                connection.BeginBinaryImport(
                    "COPY TmpTransactions(id,text) FROM STDIN(Format BINARY)"))
            {
                foreach (var dto in data)
                {
                    writer.WriteRow(dto.Id, dto.Text);
                }

                writer.Complete();
            }

            var query =
                "INSERT INTO TransactionTest select * from TmpTransactions";
        //connection.Query(query, transaction);
        connection.Execute(query);
    }

每次运行这些测试的结果总是不同的,并且无论我使用Execute()还是Query()都没关系。

Test completed. InsertBulk without transaction 1000000  elements for: 7451 ms
Test completed. InsertBulk with transaction 1000000  elements for: 4676 ms

Test completed. InsertBulk without transaction 1000000  elements for: 6336 ms
Test completed. InsertBulk with transaction 1000000  elements for: 8776 ms

我试图弄清楚它所依赖的是什么? 有任何想法吗?任何帮助表示赞赏。 谢谢。

0 个答案:

没有答案