2016-11-03 72 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)。 –