SQL Server、ODBC 18 的批量插入性能非常糟糕

问题描述 投票:0回答:1

设置:SQL Server 处于“简单”恢复模式。我还尝试禁用所有索引,但没有任何明显的性能提升,因此您可以考虑禁用它们。该服务器具有 1 个核心和 4 GB RAM。该表是堆表,没有聚集索引。

SQL Server 信息:

Microsoft SQL Server 2022 (RTM-CU14-GDR) (KB5042578) - 16.0.4140.3 (X64) 
Copyright (C) 2022 Microsoft Corporation
Enterprise Edition (64-bit) on Windows Server 2019 Standard 10.0 <X64> (Build 17763: ) (Hypervisor)

我很难加快从应用程序插入数据库的速度。我尝试了多种“批量插入”的方法:

  • 方法A:从Python调用CLR。基本上
import clr

clr.AddReference("System")
import System
# ...
bc = System.Data.SqlClient.SqlBulkCopy(...)
#... build the datatable
datatable = System.Data.DataTable()
for c in cls.columns():
    datatable .Columns.Add(name, type)
for row in data:
    dotnet_row: System.Data.DataRow = datatable.NewRow()
# ...
    dotnet_row[colname] = rowvalue
    datatable.Rows.Add(dotnet_row)
# ...
bc.DestinationTableName = ...
bc.BatchSize = 10000
bc.WriteToServer.Overloads[System.Data.DataTable](datatable)

对于 16000 行的样本,这为我提供了大约 2200 行/秒的插入速度。

  • 方法B:使用

    pandas.to_sql(...)
    。或多或少与上面相同的性能。

  • 方法C:直接从C++调用ODBC驱动程序,使用密集参数数组(我的数据没有NULL,所以它被整齐地包装):

    TRYODBC(hEnv, SQL_HANDLE_ENV, SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3_80, 0));
    // ... reading data from the filesystem, establishing connection, etc... 
    TRYRET1(hdbc, SQL_HANDLE_DBC, SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt));
    TRYRET1(hstmt, SQL_HANDLE_STMT, SQLSetStmtAttr(hstmt, SQL_ATTR_USE_BOOKMARKS, SQL_UB_OFF, 0));
    // bind by column 
    TRYRET1(hstmt, SQL_HANDLE_STMT, SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0));
    // important bit: use parameter arrays
    TRYRET1(hstmt, SQL_HANDLE_STMT, SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)data.nbRows, 0));
    // the insertion statement has a TABLELOCK
    uint32_t offset = 0;
    // starts at 1, the column 0 being the Bookmarks
    for (size_t i = 1; i <= data.headers_sizes.size(); i++)
    {
        int c_type = typemapping[data.types[i - 1]][0];
        int sql_type = typemapping[data.types[i - 1]][1];
        void* begin_array = data.rawData.data() + offset;
        // bind array of values to send to the driver
        TRYRET1(hstmt, SQL_HANDLE_STMT, SQLBindParameter(hstmt, i, SQL_PARAM_INPUT, c_type, sql_type, 0, 0, begin_array, 0, NULL));
        offset += typesizes[data.types[i - 1]] * data.nbRows;
    }
    // finally, execute.
    TRYRET1(hstmt, SQL_HANDLE_STMT, SQLExecute(hstmt));

此方法使性能翻倍,对于 16000 行的同一样本,每秒大约可以得到 4800 行。

这一切都非常悲惨。真正的问题是机器规格低(1 核、4 GB 内存)吗?我无法使用 BCP。

sql-server odbc
1个回答
0
投票

我做出了这个决定,它对我有利。上个月,我的页面因版权原因被禁用,因为我热衷于社交媒体的发展和推广。我为其他平台取样来制作自己的作品。只是繁荣! 我的帐户已关闭..我要感谢这个平台向“电子邮件”提供了很好的推荐([email protected][email protected]))..谁操作恢复和回溯日志,他访问一些在几个月不活动后进入我的帐户..需要取回系统帐户的人应该去找他...INSTAgram。 THATFIX_ERICKSON 。他对公众可靠且乐于助人..

© www.soinside.com 2019 - 2024. All rights reserved.