【问题标题】:Parameterized raw sql query much slower than query with actual values参数化的原始 sql 查询比使用实际值的查询慢得多
【发布时间】:2020-11-11 17:25:54
【问题描述】:

我正在尝试在连接到 SQL 服务器的 Django 应用程序中使用 connections[].cursor() 执行原始 sql 查询。当我在查询字符串中提供实际值时,查询的执行速度要快得多(

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()

【问题讨论】:

    标签: sql-server ssms django-pyodbc-azure


    【解决方案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)
    

    这是good link 以获取更多信息。

    【讨论】:

    • 这并没有解决我的问题。响应时间还是太长了。
    • 我提供了第二个选项,请也试试那个。
    • 非常感谢。只需声明变量就可以解决问题(即使没有 OPTION(RECOMPILE) )。
    • 很高兴它有帮助。对,使用变量时,您不需要使用选项(重新编译)。我将编辑我的答案。
    猜你喜欢
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2012-06-20
    • 2018-12-10
    相关资源
    最近更新 更多