Django - 原始 SQL 查询或 Django QuerySet ORM

Posted

技术标签:

【中文标题】Django - 原始 SQL 查询或 Django QuerySet ORM【英文标题】:Django - Raw SQL Queries or Django QuerySet ORM 【发布时间】:2019-08-05 13:21:49 【问题描述】:

我知道 Django 对象关系映射器 (ORM) 有助于弥合数据库和执行原始查询的代码之间的差距。

但我想知道哪个更好 - Raw SQL Queries 或 Django QuerySet ORM。

所以我在User Table上查询-

from django.contrib.auth.models import User

然后我查询了 Django ORM QuerySet -

orm_query = User.objects.all()
orm_query
<QuerySet [<User: superadmin>]>

在 QuerySet 之后我用户 raw -

raw_query = User.objects.raw("select * from auth_user")
raw_query
<RawQuerySet: select * from auth_user>

然后我尝试使用.query 打印这些查询,它的输出 -

print(orm_query.query)
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`

print(raw_query.query)
select * from auth_user

我发现orm_queryraw_query 长得多。 我想知道哪个是最好的raworm 查询。我应该使用哪个以获得最佳性能。它们之间有什么区别。

【问题讨论】:

在开发速度方面,使用内置的 Django ORM 会为您节省更多时间。 @DanielH。您的意思是说,为了提高开发速度,使用 django orm 和性能方面 raw 将比 queryset 工作得更好 查看我的回答了解更多详情 【参考方案1】:

由 Django 的 ORM 生成的查询会显式选择每一列,而您的原始查询会选择所有带有 * 的列。两种情况下的结果应该是相同的,你可以保持对 ORM 的查询没有任何问题。如果您想从结果中省略某些列,您仍然可以使用查询集方法 only()defer() 这将减少从数据库返回的有效负载以及将原始数据转换为 python 对象所需的工作.

您很可能只需要使用原始 sql 查询来解决 Django 的 ORM 无法解决的用例。 在大多数情况下,最大的性能影响将是由于未以正确的方式访问相关对象(有关更多信息,请参阅select_related()prefetch_related())或未正确使用indexes。另请参阅 database access optimization 上的 Django 文档。

【讨论】:

感谢您的精彩解释。我明白了,希望每个人都能得到这个问题和答案。【参考方案2】:

不管 sql 文本的长度有多长,如果你想比较性能,你应该使用类似 EXPLAIN ANALYZE 的东西(postgres 的例子),阅读答案for the mysql

dev=> EXPLAIN ANALYZE 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;
                                               QUERY PLAN                                               
--------------------------------------------------------------------------------------------------------
 Seq Scan on auth_user  (cost=0.00..10.50 rows=50 width=1527) (actual time=0.004..0.004 rows=0 loops=1)
 Planning time: 0.124 ms
 Execution time: 0.032 ms
(3 rows)

dev=> EXPLAIN ANALYZE select * from auth_user;
                                               QUERY PLAN                                               
--------------------------------------------------------------------------------------------------------
 Seq Scan on auth_user  (cost=0.00..10.50 rows=50 width=1527) (actual time=0.004..0.004 rows=0 loops=1)
 Planning time: 0.114 ms
 Execution time: 0.032 ms
(3 rows)

如您所见,Execution time 是相等的。

【讨论】:

感谢您的精彩解释。我明白了,希望每个人都能得到这个问题和答案。【参考方案3】:

一般来说,Django ORM 非常擅长执行您通常需要的数据库查询。它变得更容易并且对于复杂的查询特别有用。为这些情况编写原始查询可能会变得非常乏味和耗时。这就是为什么开发时间可能成为问题的原因。在大多数情况下,ORM 将与原始 SQL 查询一样快。所以 ORM 应该是你的默认选择。

在性能可能成为问题的少数情况下,您应该首先尝试遵循Bernhard Vallant's 答案中的建议; select_relatedprefecth_related、数据库索引等等。

【讨论】:

以上是关于Django - 原始 SQL 查询或 Django QuerySet ORM的主要内容,如果未能解决你的问题,请参考以下文章

有啥方法或包我们可以在 django 中对自定义原始 sql 查询执行过滤器(搜索)?

为啥这个 Django 原始 SQL 查询不返回输出?

Django:分页器 + 原始 SQL 查询

Django 视图中的原始 SQL 查询

Django:在一行中获取原始 SQL 查询的结果

[Django] 查看orm自己主动运行的原始查询sql