2016-11-03 44 views
2

我使用Python和当前Python3通过ANSI char/varchar columns/indexes访问legacy(读取“不会被更改”)数据库。Python3,pyodbc,SQL Server:根据需要提供Unicode和ANSI字符串

我刚刚发现一个主要的性能问题(通过一个新的数据库,我有完全控制权)通过将数据库转换为nchar/nvarchar(see this article)解决,以便我的查询,列和索引全部对齐使用Unicode格式。

哪个问题,我迄今无法谷歌它,我怎么给pyodbc一个非Unicode字符串在Python3,以便它正确地传递字符串到ODBC/SQL Server作为非Unicode串?这对许多例如显着的性能影响数据挖掘应用程序。

这似乎工作,但它是正确的?

conn = pyodbc.connect(connection_string) 
curr = conn.cursor() 
aString = 'Howdy!' 
query = 'select * from aTable where aColumn = ?' 
results = curr.execute(q, [aString.encode('ascii')]) 

另外/另外,是否更适合和/或可能在SQL Server中的非Unicode列上构建Unicode索引? (我有足够的数据库控制来添加索引)。

回答

1

它正确吗?

基于SQL Profiler和SQL Server Management Studio(SSMS)在Windows下使用SQL Server ODBC进行测试时所说的内容,假设字符串值确实将被限制为ASCII字符,似乎是这样。

如果我们只是通过[aString]作为查询参数,SQL事件探查器显示pyodbc发送此

exec sp_prepexec @p1 output,N'@P1 nvarchar(6)',N'select * from aTable where aColumn = @P1',N'Howdy!' 

,如果我们问SSMS向我们展示了估计的执行计划

select * from aTable where aColumn = N'Howdy!' 

它告诉我们它期望进行索引扫描。

然而,如果我们通过[aString.encode('ascii')]作为查询参数,SQL事件探查器显示pyodbc发送此

exec sp_prepexec @p1 output,N'@P1 varbinary(6)',N'select * from aTable where aColumn = @P1',0x486F77647921 

,如果我们问SSMS向我们展示了估计的执行计划

select * from aTable where aColumn = 0x486F77647921 

它告诉我们,它期望做一个索引寻求。

“寻找”通常比“扫描”更好,所以如果查询实际返回正确的结果,我希望使用编码参数可以获得更好的性能。

+0

你把我的“证明它有效”进一步实验,但你的答案并不令人满意。特别是,我担心SQL Server将查询视为varbinary而不是varchar/char。最后,我想知道如何正确地将ANSI字符串提供给ANSI数据库,和/或针对Unicode查询的性能保护ANSI数据库。 – Andreus

+0

兴趣点:Python2下的pyodbc执行'exec sp_prepexec @ p1输出,N'@P1 varchar(6)',N'SELECT * FROM aTable WHERE aColumn = @ P1','Howdy!''。但是,Python3没有“纯”(非Unicode)字符串,只有“字符串”(对于Unicode)和“字节”(对于非Unicode)。 –