我正在尝试在连接到 SQL Server 的 Django 应用程序中使用connections[].cursor() 执行原始sql 查询。查询执行速度更快 (<1s) when I provide the actual vlaues in the query string.
from django.db import connections
with connections['default'].cursor() as cursor:
cursor.execute("""
select c.column1 as c1
, ve.column2 as c2
from view_example c
left join view_slow_view ve on c.k1 = ve.k2
where c.column_condition = value_1 and c.column_cd_2 = value2
""")
result = dictfetchall(cursor)
但是当我在cursor.execute()方法中提供值作为params时,查询变得慢得多(2分钟)。
from django.db import connections
with connections['default'].cursor() as cursor:
cursor.execute("""
select c.column1 as c1
, ve.column2 as c2
from view_example c
left join view_slow_view ve on c.k1 = ve.k2
where c.column_condition = %s and c.column_condition_2 = %s
""", [value_1, value_2])
contracts_dict_lst = dictfetchall(cursor)
我还应该提到,仅当未提供条件时,在 SSMS 上执行查询时实际上很慢:
where c.column_condition = value_1 and c.column_cd_2 = value2
就好像Django发送查询时,是在不带参数的情况下执行的(因此响应时间很长),然后提供参数,以便过滤结果。
有问题的值是由用户提供的,因此它们会发生变化,并且必须作为参数传递,而不是直接在查询中传递,以避免 SQL 注入。 该查询也比上面给出的示例复杂得多,并且不能清楚地映射到模型,因此我必须使用connection[].cursor()
这可能是参数嗅探问题。如果是这种情况,有两种解决方案。最简单的解决方案是使用查询提示。
选项1:
from django.db import connections
with connections['default'].cursor() as cursor:
cursor.execute("""
select c.column1 as c1
, ve.column2 as c2
from view_example c
left join view_slow_view ve on c.k1 = ve.k2
where c.column_condition = %s and c.column_condition_2 = %s
OPTION(RECOMPILE) -- add this line to your query
""", [value_1, value_2])
contracts_dict_lst = dictfetchall(cursor)
选项2:
from django.db import connections
with connections['default'].cursor() as cursor:
cursor.execute("""
declare v1 varchar(100) = %s -- declare variable and use them
declare v2 varchar(100) = %s
select c.column1 as c1
, ve.column2 as c2
from view_example c
left join view_slow_view ve on c.k1 = ve.k2
where c.column_condition = v1 and c.column_condition_2 = v2
""", [value_1, value_2])
contracts_dict_lst = dictfetchall(cursor)
这是一个很好的链接,可供更多阅读。
msql = "Select count(1) as Bil from customer where AcctNo = '" + ACCTNO +"'"
不要使用 AcctNo 参数执行。
下面会运行得更慢:
result = cursor1.execute('Select count(1) as Bil from customer where AcctNo = ?', ACCTNO)
我也有类似的问题。对于大型数据集尤其会发生这种情况,因为驱动程序从 Python 获取 unicode 值,并使用
NVARCHAR
来实现更广泛的兼容性。现在,这意味着在 NVARCHAR
子句中进行比较时,查询必须临时将每个列值(从相应的参数)转换为
where
。我的解决方法是在查询中强制转换,这就是我在下面提供选项 3的原因。
选项3:
from django.db import connections
with connections['default'].cursor() as cursor:
cursor.execute("""
select c.column1 as c1
, ve.column2 as c2
from view_example c
left join view_slow_view ve on c.k1 = ve.k2
where c.column_condition = CAST(%s as VARCHAR(100) and c.column_condition_2 = CAST(%s as VARCHAR(100)
""", [value_1, value_2])
contracts_dict_lst = dictfetchall(cursor)