我正在运行Python pyodbc对SQL Server。这里有一个非常复杂的查询,我将其最小化为
DECLARE @mydate DATETIME = '2021-02-08'
SELECT *
FROM atable
WHERE adate = @mydate AND afield = ?
在Python端,我执行的是常规的
crsr.execute(sql, field)
令我困惑的是,它返回所有结果,它忽略了条件,但有一个奇怪的顺序,所以当我绘制图形时,它非常困惑!为什么会这样呢?(编辑当然我应该加上afield = field
,没有其他错误ORDER BY
)
我已经用一个初始
固定了代码DECLARE @myfield VARCHAR(32) = ?
后面跟着以afield=@myfield
结尾的where条件,现在它像预期的那样工作了:即使我没有引入显式的ORDER BY
,顺序也是正常的。
换句话说,除了最终正确的修复是添加ORDER BY
之外,例如
SELECT *
FROM atable
WHERE adate = @mydate AND afield = ?
ORDER BY id
我想知道为什么引入上述变化足以改变顺序。
因为您的SQL连接驱动程序似乎不支持适当的参数,所以它将参数嵌入为文本。我不知道它的消毒和转义方法有多好,但由于SQL注入的风险,这通常不是一个好主意。
我注意到
pymssql
驱动程序支持命名参数
可能发生的情况是,当编译器可以看到您想要使用的确切值时,它将计算可能匹配的行数("基数")的统计信息,因此它可能根据可用的索引选择不同的访问模式。
当该值作为一个适当的参数出现时(当使用一个好的SQL驱动程序时),该参数将被"嗅探",编译器将在第一次运行查询时使用基于该值的统计信息。如果有一个常用的值,这将是有益的。
如果值在一个局部变量中,则不使用参数嗅探,编译器使用该谓词的平均基数。这可能比"嗅探"好,也可能比"嗅探"差。
听起来嵌入值更好。但是不是的情况。
当嵌入值时,每个查询都是独立的,并且每次都必须重新编译。这会对执行时间和CPU使用以及保存查询计划的内存使用产生很大的影响。