Если вы используете Python_3, тогда все строки в Unicode. Код Python ...
sql = "SELECT * FROM MillionRows WHERE varchar_column = ?"
crsr.execute(sql, 'record012345')
... обрабатывается на SQL Server как
declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,N'@P1 nvarchar(24)',N'SELECT * FROM MillionRows WHERE varchar_column = @P1',N'record012345'
select @p1
Обратите внимание, что значением параметра является Unicode: nvarchar(24)
Теперь, если мы проверим фактический план выполнения эквивалентного запроса в SSMS ...
SELECT * FROM MillionRows WHERE varchar_column = N'record012345'
... мы увидим
Physical operation: Index Scan
Actual Number of Rows: 1
Number of Rows Read: 1000000
С другой стороны, если мы запустимзапрос, который использует varchar
значение ...
SELECT * FROM MillionRows WHERE varchar_column = 'record012345'
... план выполнения показывает нам
Physical operation: Index Seek
Actual Number of Rows: 1
Number of Rows Read: 1
Разница заключается в том, что первый запрос должен выполнитьСканирование для (неявно преобразованного) значения nvarchar
по индексу varchar
, в то время как второй запрос может выполнять поиск вместо сканирования.
Исправление для необработанного кода Python заключается в использовании setinputsizes , чтобы указать, что параметр запроса должен быть varchar
...
sql = "SELECT * FROM MillionRows WHERE varchar_column = ?"
crsr.setinputsizes([(pyodbc.SQL_VARCHAR, 25)])
crsr.execute(sql, 'record012345')
.., который обрабатывается на SQL Server как
declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,N'@P1 varchar(25)',N'SELECT * FROM MillionRows WHERE varchar_column = @P1','record012345'
select @p1
Обходной путь для панд read_sql_query
заключается в CAST
значении параметра в самом запросе SQL
sql = "SELECT * FROM MillionRows WHERE varchar_column = CAST(? AS varchar(25))"
df = pd.read_sql_query(sql, engine, params=['record012345'])