0

我正在尝试在连接到 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() 方法中将值作为参数提供时,查询会变得慢得多(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()

4

1 回答 1

1

这可能是参数嗅探问题。如果是这种情况,有几个解决方案。最简单的解决方案是使用查询提示。

选项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)

这是更多阅读的好链接

于 2020-11-11T17:46:02.220 回答