参数化原始 sql 查询比使用实际值的查询慢得多
Parameterized raw sql query much slower than query with actual values
我正在尝试在连接到 SQL 服务器的 Django 应用程序中使用 connections[].cursor() 执行原始 sql 查询。当我在查询字符串中提供实际值时,查询执行得更快 (<1s)。
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)
这是一个good link供更多阅读。
我正在尝试在连接到 SQL 服务器的 Django 应用程序中使用 connections[].cursor() 执行原始 sql 查询。当我在查询字符串中提供实际值时,查询执行得更快 (<1s)。
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)
这是一个good link供更多阅读。