如何查看Django正在运行的原始SQL查询?

How can I see the raw SQL queries Django is running?

有没有一种方法可以显示执行查询时Django正在运行的SQL?


请参阅docs常见问题解答:"如何查看django正在运行的原始SQL查询?"

django.db.connection.queries包含一个SQL查询列表:

1
2
FROM django.db import connection
print connection.queries

查询集还具有包含要执行的查询的query属性:

1
print MyModel.objects.filter(name="my name").query

请注意,查询的输出不是有效的SQL,因为:

"Django never actually interpolates the parameters: it sends the query and the parameters separately to the database adapter, which performs the appropriate operations."

来自Django Bug报告17741。

因此,不应将查询输出直接发送到数据库。


看看调试工具栏,它对调试非常有用。

文档和源可以在http://django debug toolbar.readthedocs.io/上找到。

Screenshot of debug toolbar


django扩展有一个命令shell_plus和一个参数print-sql

1
./manage.py shell_plus --print-sql

在django shell中,将打印所有执行的查询

前任。:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
USER.objects.get(pk=1)
SELECT"auth_user"."id",
      "auth_user"."password",
      "auth_user"."last_login",
      "auth_user"."is_superuser",
      "auth_user"."username",
      "auth_user"."first_name",
      "auth_user"."last_name",
      "auth_user"."email",
      "auth_user"."is_staff",
      "auth_user"."is_active",
      "auth_user"."date_joined"
FROM"auth_user"
WHERE"auth_user"."id" = 1

Execution TIME: 0.002466s [DATABASE: DEFAULT]

<USER: username>


1
2
3
q = Query.objects.values('val1','val2','val_etc')

print q.query


没有其他答案包含此方法,因此:

我发现到目前为止最有用、最简单、最可靠的方法是询问您的数据库。例如,在Linux for Postgres上,您可以执行以下操作:

1
2
sudo su postgres
tail -f /var/log/postgresql/postgresql-8.4-main.log

每个数据库的过程略有不同。在数据库日志中,您不仅可以看到原始SQL,还可以看到Django在系统上设置的任何连接设置或事务开销。


尽管您可以使用提供的代码来完成这项工作,但我发现使用调试工具栏应用程序是显示查询的一个很好的工具。你可以在这里从Github下载。

这使您可以选择显示在给定页面上运行的所有查询以及所用的查询时间。它还总结了一个页面上的查询数以及快速查看的总时间。这是一个很好的工具,当你想看看Django ORM在幕后做了什么。它还有很多其他不错的功能,如果你愿意的话,你可以使用。


另一个选项,请参见本文描述的settings.py中的logging options。

http://dabapps.com/blog/logging-sql-queries-django-13/

调试工具栏会降低dev服务器上的每个页面加载速度,日志记录不会降低速度。输出可以转储到控制台或文件中,因此用户界面不是很好。但是对于具有大量SQL的视图,通过调试工具栏调试和优化SQL可能需要很长的时间,因为每个页面加载都很慢。


如果确保settings.py文件具有:

  • django.core.context_processors.debug列在CONTEXT_PROCESSORS
  • 江户十一〔四〕号
  • 你的IPINTERNAL_IPS元组中
  • 然后您应该可以访问sql_queries变量。我在每个页面上附加了一个页脚,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    {%IF sql_queries %}
     
        Queries
        <p>

          {{ sql_queries|LENGTH }} Quer{{ sql_queries|pluralize:"y,ies" }}, {{sql_time_sum}} TIME
        {% ifnotequal sql_queries|LENGTH 0 %}
          (<span STYLE="cursor: pointer;" onclick="var s=document.getElementById('debugQueryTable').style;s.disp\
    lay=s.display=='none'?'':'none';this.innerHTML=this.innerHTML=='Show'?'Hide':'Show';"
    >Show</span>)
        {% endifnotequal %}
       
    </p>
        <TABLE id="debugQueryTable" STYLE="display: none;">
          <col width="1"></col>
          <col></col>
          <col width="1"></col>
          <thead>
            <tr>
              <th scope="col">#</th>
              <th scope="col">SQL</th>
              <th scope="col">Time</th>
            </tr>
          </thead>
          <tbody>
            {% FOR query IN sql_queries %}
              <tr class="{% cycle odd,even %}">
                <td>{{ forloop.counter }}</td>
                <td>{{ query.sql|escape }}</td>
                <td>{{ query.time }}</td>
              </tr>
            {% endfor %}
          </tbody>
        </table>
     
    {% endif %}

    我通过添加行得到了变量sql_time_sum

    1
    context_extras['sql_time_sum'] = SUM([FLOAT(q['time']) FOR q IN connection.queries])

    到django_src/django/core/context_processors.py中的调试函数。


    为此,我开发了一个扩展,这样您就可以轻松地在视图函数上放置一个修饰器,并查看执行了多少查询。

    要安装:

    1
    $ pip install django-print-SQL

    要用作上下文管理器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    FROM django_print_sql import print_sql

    # SET `count_only` TO `True` will print the NUMBER OF executed SQL statements ONLY
    WITH print_sql(count_only=FALSE):

      # WRITE the code you want TO analyze IN here,
      # e.g. SOME complex FOREIGN KEY lookup,
      # OR analyzing a DRF serializer's performance

      for user in User.objects.all()[:10]:
          user.groups.first()

    用作装饰:

    1
    2
    3
    4
    5
    6
    FROM django_print_sql import print_sql_decorator


    @print_sql_decorator(count_only=FALSE)  # this works ON class-based views AS well
    def GET(request):
        # your VIEW code here

    github:https://github.com/rabbit-aron/django-print-sql


    如果您使用PostgreSQL,我相信这应该是可行的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    FROM django.db import connections
    FROM app_name import models
    FROM django.utils import timezone

    # Generate a queryset, USE your favorite FILTER, QS objects, AND whatnot.
    qs=models.ThisDataModel.objects.filter(USER='bob',date__lte=timezone.now())

    # GET a cursor tied TO the DEFAULT DATABASE
    cursor=connections['default'].cursor()

    # GET the query SQL AND parameters TO be passed INTO psycopg2, THEN pass
    # those INTO mogrify TO GET the query that would have been sent TO the backend
    # AND print it OUT. Note F-strings require python 3.6 OR later.
    print(f'{cursor.mogrify(*qs.query.sql_with_params())}')


    根据https://code.djangoproject.com/ticket/17741,下面将查询返回为有效的SQL:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def str_query(qs):
       """
        qs.query returns something that isn't valid SQL, this returns the actual
        valid SQL that's executed: https://code.djangoproject.com/ticket/17741
       "
    ""
        cursor = connections[qs.db].cursor()
        query, params = qs.query.sql_with_params()
        cursor.execute('EXPLAIN ' + query, params)
        res = str(cursor.db.ops.last_executed_query(cursor, query, params))
        assert res.startswith('EXPLAIN ')
        RETURN res[len('EXPLAIN '):]


    我做了一个小片段,你可以用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    FROM django.conf import settings
    FROM django.db import connection


    def sql_echo(method, *args, **kwargs):
        settings.DEBUG = TRUE
        RESULT = method(*args, **kwargs)
        FOR query IN connection.queries:
            print(query)
        RETURN RESULT


    # HOW TO USE EXAMPLE:
    #
    # RESULT = sql_echo(my_method, 'whatever', SHOW=TRUE)

    它将作为参数函数(包含SQL查询)进行检查,并使用调用该函数所需的参数、Kwarg。因此,它返回函数返回的内容,并在控制台中打印SQL查询。


    我只需执行以下操作就可以看到失败的查询:

    1
    tail -f /var/log/postgresql/*

    假设postgres 10.6、ubuntu 18.04+、python3+、django2+,并且在postgres中启用了日志记录。