mssql-python 加载两个原生ODBC提供商之一:
| Provider | 它是什么 | Status |
|---|---|---|
msodbcsql18 |
Microsoft ODBC 驱动 18 for SQL Server,成熟的 C++ 驱动程序 | 默认,未变 |
mssql-odbc |
一个用Rust编写的新ODBC驱动 | 预览,选择启用 |
本文涵盖mssql-odbc0.3.0版本、当前由mssql-python使用的版本,以及它与msodbcsql18的不同之处。
Note
mssql-odbc 正在积极开发和验证中。 它还不是 Microsoft ODBC Driver 18 的完全替代品。 暂时保持 msodbcsql18 作为生产默认。 开发团队计划在即将发布的版本中弥补预览空白,但本文中明确指出的有意排除项除外。
Availability
驱动程序以预构建的 wheel 包形式包含在 mssql-python-rs 软件包中,适用于 CPython 3.10 及更高版本:
| Platform | Architectures |
|---|---|
| Windows | x64;CPython 3.11+ 上的 ARM64 |
| macOS | Universal 2(x86_64 + arm64),macOS 15 或更高版本 |
| Linux (glibc) | x86_64,aarch64—— manylinux_2_28 和 manylinux_2_34 |
| Linux(musl) | x86_64,aarch64 — musllinux_1_2 |
启用驱动程序
该 mssql-python 软件包依赖于 mssql-python-rs,因此正常安装会附带 Rust 驱动:
pip install mssql-python
如果你用 --no-deps 安装,或从私有索引安装,也要明确安装 mssql-python-rs 。
在 第一个连接之前选择提供者,可以使用环境变量:
PowerShell:
$env:MSSQL_PYTHON_NATIVE_PROVIDER = "mssql-odbc"
Bash 或 Zsh:
export MSSQL_PYTHON_NATIVE_PROVIDER=mssql-odbc
或者在 Python 中:
import mssql_python
mssql_python.native_provider = "mssql-odbc"
使用应用程序现有的连接字符串进行连接。 保持启用证书验证(Encrypt=yes;TrustServerCertificate=no)。 关于认证和证书设置,请参见 连接字符串 和 加密与证书。
connection = mssql_python.connect(connection_string)
驱动程序在选择提供程序时适用以下规则:
-
MSSQL_PYTHON_NATIVE_PROVIDER环境变量优先于native_provider。 冲突的属性赋值会输出RuntimeWarning。 - 选择在连接字符串验证后且在构建原生连接之前变得固定。 后续的连接失败不会清除该选择。 早期的连接字符串解析错误或缺少提供程序包并不能修复所选内容。 选择被固定后,将
native_provider更换为其他供应商会发出RuntimeWarning信号,且不会产生任何影响。 重新启动该流程以切换提供程序。 - 未识别的服务提供商名称会引发
ValueError;驱动程序不会回退到默认提供商。 给native_provider分配未知名称时会立即引发错误。 当你尝试连接时,环境变量中存在未知名称会引发错误。 - 将
native_provider设置为None,以在属性选择固定之前将其清除。 环境变量依然优先。
调用 mssql_python.get_native_provider_info() 以检查所选提供程序、选择来源,以及选择是否固定。 连接前,这会报告选择情况,而不是本地驱动成功加载的证明。
要返回,可以将变量设置为 msodbcsql18,或者取消设置,并从代码中移除任何对 native_provider 的赋值(或将其设置为 "msodbcsql18")。
然后重新开始这个过程。
当前可行的做法
mssql-odbc驱动程序实现了mssql-python调用的所有 ODBC 函数,因此大多数应用可以在不修改代码的情况下切换提供程序。 查看 已知问题 以了解剩余差异。
| Area | 备注 |
|---|---|
| 连接生命周期 | 连接、close()、with 块、登录超时、诊断以及更改当前数据库。 连接字符串设置包括 IpAddressPreference、PacketSize、KeepAlive、ConnectRetryCount、 / 和 ConnectRetryIntervalMultiSubnetFailoverApplicationIntent(空闲连接弹性)。 |
| Authentication | SQL 认证(UID / PWD);Windows 身份验证(Trusted_Connection=Yes,在 Windows 上使用 SSPI,在 Linux 和 macOS 上使用 Kerberos);以及 Microsoft Entra 交互式、设备代码、服务主体、托管身份、默认凭据和访问令牌。 Entra 集成和密码身份验证不受支持;参见已知问题。 |
| TLS |
Encrypt、TrustServerCertificate、HostnameInCertificate 和 ServerCertificate。 |
| 查询执行 | 直接执行、预处理执行、预处理计划的重复使用、qmark 参数,以及 pyformat 转换 mssql-python 的执行。 |
| ODBC 转义语法 | 函数、日期/时间、外连接、GUID、LIKE ... {escape ...}、区间和 {encrypt ...} 转义形式。 |
| 存储过程 | 用 T-SQL 或通过 execute() 的位置语法 {call ...} 调用它们,读取结果集,然后用 nextset() 推进。 |
| 输入参数 | 标量参数、SQL NULL、SQL setinputsizes() 以及混合的常规/流式参数。 |
| 较大参数 | 大文本和二进制参数通过普通绑定路径传输到服务器;XML和UDT参数的限制如下。 |
executemany() |
使用 ODBC 参数数组批量处理。 包含流式值的行会回退为逐行执行。 |
| 行提取 |
fetchone(), fetchmany(), fetchall(), 迭代, fetchval(), 类型转换,以及大文本/二进制流式。 |
| 箭头获取 |
arrow_batch()、 arrow()和 arrow_reader()。 需要 pyarrow。 |
| 多个结果集 |
nextset(),包括参数数组产生的结果。 |
| Transactions | 自动提交、提交、回滚、在块 with connect(...) 结束时发生的自动提交(或如果有错误时回滚),以及读未提交、读已提交、可重复读、可序列化和快照隔离级别。 |
| 查询超时 | 将 Connection.timeout(以秒为单位)设置为该连接的游标所执行语句的时间限制;到期时会引发 OperationalError。
0 表示没有超时。 此设置与通过 connect(timeout=...) 传递的登录超时是分开的。 |
| 连接池 | 内置mssql-python连接池,包括从池中获取连接时重置连接,以及针对每个 Microsoft Entra 标识的独立池。 |
| 元数据 API |
tables()、、columns()、primaryKeys()foreignKeys()、statistics()、rowIdColumns()、rowVerColumns()、、 procedures()和getTypeInfo()。 |
| 编码与转换工具 | 默认宽字符编码和输出转换器。 自定义窄字符解码和非Unicode参数转换的限制列于已知问题。 |
数据类型
你可以读取所有 SQL Server 数据类型,驱动也支持 mssql-python 绑定的所有参数类型。 驱动程序将 xml、vector 和 vector 值作为 str 返回(geometry 作为 JSON 数组),并将 geography、hierarchyid 和 bytes 等 CLR 类型作为 json 返回。 关于其他 Python 映射,请参见数据类型映射。
关于类型特定的限制,请参见 已知问题。
已知问题
在从 msodbcsql18 切换工作负载前,先检查这些差异。
| Issue | Details | Workaround |
|---|---|---|
| Microsoft Entra 集成身份验证 | 不支持 Authentication=ActiveDirectoryIntegrated。 Windows 身份验证(Trusted_Connection=Yes)不受影响。 |
使用其他 Microsoft Entra 方法,或者保留 msodbcsql18。 |
| Microsoft Entra 密码身份验证 |
Authentication=ActiveDirectoryPassword 不支持,也没有计划支持,因为这种方法无法满足多重身份验证。 SQL认证(UID / PWD)不受影响。 |
可以使用其他 Microsoft Entra 方法,比如服务主体、托管身份或访问令牌。 |
attrs_before设置 |
认证、应用意图和多子网故障转移不能作为数字属性设置。 除查询超时外,其他语句属性都不被接受。 | 使用等效的连接字符串关键词。 |
| 连接操作超时 |
set_attr(SQL_ATTR_CONNECTION_TIMEOUT, ...) 接受并存储该值,但在 0.3.0 中不会强制执行超时机制。 |
用于 connect(timeout=...) 登录和 Connection.timeout 语句;这两者都不是通用连接操作超时时间。 |
| 多地址主机 |
msodbcsql18 默认启用透明网络 IP 解析(TNIR);mssql-odbc 不支持 TNIR。
mssql-python 在使用任一提供程序时都会拒绝 TransparentNetworkIPResolution 连接字符串关键字。 没有 MultiSubnetFailover=Yes,地址一次只尝试一个,因此无法到达的地址可能会延迟连接。 服务器辅助的DNS缓存和增强路由不会被协商。 |
为可用性组监听器和其他多地址主机设置 MultiSubnetFailover=Yes。 |
| DNS 暂时性故障 | 如果DNS查询失败,驱动不会回退到最后成功地址。 (#457) | 重试连接。 |
| 数据分类 | 敏感度分类元数据不可用,并且不支持 SQL_COPT_SS_DATACLASSIFICATION_VERSION (1400)。 |
查询 sys.sensitivity_classifications。 |
| 多线程 | 多线程使用尚未被验证。 | 为多线程工作负载保留 msodbcsql18。 |
fork() 连接后 |
在 Linux 上,父进程连接后 fork 出的进程在使用驱动时可能会卡住,即使使用新的连接。 启用池化后,父节点也会挂起。 (#566) | 使用 spawn 启动方法,并在每个工作线程内部连接。 |
| 取消正在运行的报表 | 正在进行的查询或提取不能被中断。 例如,关闭 arrow_reader() 并不会停止另一个线程中正在进行的读取操作。 |
使用 Connection.timeout 来限制长时间运行的语句。 |
| 未读结果 | 关闭光标或运行另一个语句会读取并丢弃剩余结果,而不是取消这些结果,这可能会很慢。 关闭使用预备语句的光标会忽略 Connection.timeout,并可能在服务器停止响应时挂起。 (#546) |
只取你需要的行,例如使用TOP。 |
| 大型参数和 UDT 参数 | 作为 SQL_SS_XML 或通过 SQL_SS_UDT 到 setinputsizes() 绑定的值会缓冲在内存中,而不是以流方式传输。 |
将 xml 值作为普通字符串绑定。 |
空 image 值 |
一个空的、非NULL的SQL Serverimage值被返回为None,而非b""。 |
阅读 CAST(image_column AS varbinary(max)),或者在空值/NULL 的区别很重要时使用 msodbcsql18。 |
| 非Unicode字符串参数 | 绑定为 char / varchar 到 setinputsizes() 的字符串在代码页 437、代码页 850 和 UTF-8 排序中可能被错误编码。 |
使用默认字符串绑定。 |
| Windows上的遗留代码页解码 | 使用 setdecoding(SQL_CHAR, encoding="cp1252") 或其他遗留代码页时,文本可能被错误解码或返回为 bytes,因为驱动程序将 char / varchar 数据作为 UTF-8 返回。 |
使用默认的: conn.setdecoding(mssql_python.SQL_CHAR)。 |
Connection.getinfo() |
SQL_USER_NAME 返回连接字符串 UID,而不是数据库用户。 当没有 UID 到达驱动程序时,它是空的。 某些能力值和基于数据包大小的限制与 msodbcsql18不同。 |
将 SELECT USER_NAME() 用作数据库用户。 |
| 内存耗尽错误 | 一些驱动程序分配失败会终止 Python 进程,而不是引发MemoryError异常。 (#484) |
限制你发送和取回的值大小。 |
| 大值读取性能 | 在一项基准测试中,数据分块读取varchar(max) / nvarchar(max)速度略慢于使用msodbcsql18时。 (#473) |
对你的工作负载进行基准测试。 |
此列表并不详尽。
报告问题
如果遇到缺陷,选择 msodbcsql18,重启进程,检查该行为是否仍然存在。 同时移除任何冲突的 Python 端提供者分配。 这种比较有助于定位问题;它本身并不能证明其根源。 请附上 mssql_python.get_native_provider_info() 的输出、您的平台以及失败的 SQL 或错误信息:
- Rust驱动问题: https://github.com/microsoft/mssql-rs/issues
-
mssql-python问题: https://github.com/microsoft/mssql-python/issues
对于 Rust 驱动的诊断,在启动 Python 前先设置这些变量,并在选中 mssql-odbc 的情况下重现问题。 例如,在 PowerShell 中:
$env:MSSQL_TDS_TRACE = "true"
$env:MSSQL_TDS_TRACE_LEVEL = "warn,mssqlodbc=debug"
$env:MSSQL_TDS_TRACE_DIR = "./traces"
MSSQL_TDS_TRACE 启用追踪, MSSQL_TDS_TRACE_LEVEL 选择日志过滤器,并 MSSQL_TDS_TRACE_DIR 写入每个进程的文件而非 stderr。
更改这些设置后重启 Python。 追踪可以包含SQL文本和参数值。 在分享相关摘录前,请审查并遮蔽敏感数据,诊断后关闭追踪功能。