sp_execute_external_script 是唯一入口,必须启用外部脚本、使用绝对路径存放模型、通过@input_data_1传入数据、输出赋值给OutputDataSet DataFrame,且模型序列化版本与SQL Server内置Python及sklearn版本严格兼容。

sp_execute_external_script 是唯一入口,但直接在存储过程中“调用已训练模型”不是简单粘贴 joblib.load() 就能跑通的——SQL Server 对 Python 运行时、路径、权限和数据流有硬性约束。
必须先确认外部脚本功能已启用且 Python 已安装
sp_configure 返回 external scripts enabled 值为 0 表示禁用,需 DBA 权限执行:
EXEC sp_configure 'external scripts enabled', 1; RECONFIGURE WITH OVERRIDE;
该操作仅开启接口,不自动安装 Python。SQL Server 2017(14.x)RTM–CU21 自带 Python 3.5.2;CU22+ 同时支持 3.5.2 和 3.7.2。若未在安装时勾选“机器学习服务(Python)”,后续无法增量添加——必须重装或打补丁。
立即学习“Python免费学习笔记(深入)”;
模型不能放在任意路径,必须用 SQL Server 可读的绝对路径
SQL Server 的 Launchpad 服务以低权限账户(如 SQLRUserGroup)运行,无法访问用户桌面、OneDrive、映射网络盘或未授权的 NTFS 路径。
- ✅ 推荐存放位置:
C:Program FilesMicrosoft SQL ServerMSSQL14.MSSQLSERVERPYTHON_SERVICES下新建models子目录 - ❌ 禁止路径:
C:UsersAlicemodels、serversharemodel.pkl、D: emp(除非显式授予 Launchpad 账户读取权限)
加载代码必须用原始字符串避免转义错误:
@script = N'import pickle; import os; model_path = r"C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\PYTHON_SERVICES\models\rf_model.pkl"; with open(model_path, "rb") as f: model = pickle.load(f)'
注意双反斜杠 或前缀 r"",否则 m 会被解释为转义字符。
输入数据只能走 @input_data_1,输出必须是 pandas DataFrame
sp_execute_external_script 不支持 sys.argv、命令行参数或 stdin/stdout 传参。所有输入必须通过 T-SQL 查询注入:
-
@input_data_1 = N'SELECT feature1, feature2 FROM dbo.score_input WHERE batch_id = 123' - 在 Python 中,该结果自动绑定为变量
InputDataSet(R 下是InputDataSet,Python 下默认也是,但可被@input_data_1_name覆盖)
输出必须赋值给 OutputDataSet(变量名固定),且类型必须是 pandas.DataFrame:
@script = N'import pandas as pd; OutputDataSet = pd.DataFrame({"score": model.predict(InputDataSet)})'
若返回 dict/list/scalar,会报错 TypeError: 'dict' object does not support indexing 或静默失败无结果。
模型序列化格式要兼容 Python 版本与环境
SQL Server 2017 自带的 Python 3.5.2 无法加载用 Python 3.8+ 保存的 pickle 文件(协议版本不兼容)。也不能直接用 joblib —— 它未预装,需提前用 sqlmlutils 或管理员权限在服务器上安装:
pip install --target "C:Program FilesMicrosoft SQL ServerMSSQL14.MSSQLSERVERPYTHON_SERVICESLibsite-packages" joblib
更稳妥的做法是:用训练环境(Python 3.5.2)导出模型,或改用纯 Python 标准库方案(如 pickle + scikit-learn 0.20.x,它对协议版本较宽容)。
真正容易被忽略的是:模型文件本身可能依赖训练时的模块版本。比如用 sklearn 0.24 训练的模型,在 SQL Server 的 sklearn 0.20 上 pickle.load() 会抛 ModuleNotFoundError 或 AttributeError。必须核对 pip list 输出并锁定版本。


















