您现在的位置是:百科 >>正文

django查询数据库

百科6553人已围观

简介Django的ORM查询系统,本质上是一层Python与SQL之间的翻译官。但很多人用着用着就忘了这回事,把ORM当成万能工具,写出来的查询慢得像蜗牛爬。 先看个真实例子。我接手过一个项目,首页加载要 ...

Django的查询ORM查询系统,本质上是数据一层Python与SQL之间的翻译官。但很多人用着用着就忘了这回事,查询把ORM当成万能工具,数据写出来的查询查询慢得像蜗牛爬。

先看个真实例子。数据我接手过一个项目,查询首页加载要4秒。数据翻代码,查询发现有个视图在循环里查了20次数据库——每次循环都执行一次QuerySet。数据这就是查询经典N+1查询问题。解决方案很简单,数据用select_related()或prefetch_related()把关联数据一次性捞出来。查询改完之后,数据响应时间降到300毫秒。查询就这么粗暴有效。

但别急着把所有查询都加上select_related。有个同事曾经把所有外键都塞进select_related,结果查一个列表页,SQL变成了六个表的巨型JOIN,数据量一大直接超时。select_related适合“一对一”或“多对一”关系,比如Article和Author。而prefetch_related更适合“多对多”或“反向外键”,比如Article和Tag。它分两条SQL查,然后在Python里做拼接,反而更灵活。

再说说values()和only()的取舍。很多人习惯直接Model.objects.all(),然后取字段。但如果你只需要id和name两个字段,却把整个表所有列都拉回来,数据库IO和内存都白费。用values('id', 'name')返回的是字典,不是模型实例,速度更快。但代价是失去模型方法。如果只是渲染数据,完全够用。

有个坑我得提醒你——count()和exists()的区别。判断记录是否存在时,有人写if queryset.count() > 0,这会让数据库执行完整的COUNT操作。而queryset.exists()会翻译成LIMIT 1,查到一条就停。数据量大时,性能差异是数量级的。我见过一个统计页面,用count()判断空表,每次查询要扫全表,改成exists()后秒开。

还有filter的链式调用,看着优雅,但别滥用。Django的QuerySet是惰性的,链式调用不会立刻执行SQL,直到你迭代它或调用len()、list()等方法。但如果你在循环里反复对同一个QuerySet做filter,每次filter都会生成新的SQL,不会复用之前的结果。正确做法是先qs = Model.objects.filter(...),然后循环里只对qs做切片或排序,而不是再filter。

最后说个冷门但实用的技巧。annotate()配合F()表达式,能在数据库层面做字段间的计算,避免把数据拉到Python里再算。比如统计每个作者的活跃天数,用F('last_login') - F('date_joined'),数据库直接算好,返回timedelta。这比遍历所有用户再在Python里减要快得多。

说到底,Django ORM是个好工具,但你要理解它底层的SQL逻辑。别迷信“ORM自动优化”,它只做你让它做的事。写查询前先想想:这条SQL会怎么执行?需要哪些索引?数据量多大?多问自己一句,就能避免很多性能事故。

Tags:

相关文章

  • 怎么扒网站源码

    百科

    浏览器里按下F12,开发者工具弹出的瞬间,大多数人的第一反应是关掉它。但扒源码这件事,其实没你想的那么玄乎——它跟拆快递差不多,只需要一把剪刀和一点耐心。 我见过最离谱的扒站方式,是有人用“查看网页源 ...

    【百科】

    阅读更多
  • 市场渗透定价法不强调利润对成本的弥补

    百科

    亚马逊Kindle刚上市时卖399美元,这个价格连硬件成本都盖不住。贝索斯在接受采访时说得很直白:我们不指望靠卖设备赚钱,我们要的是用户进来买电子书。这就是市场渗透定价法的核心逻辑——用低价快速铺开市 ...

    【百科】

    阅读更多
  • 软件无限试用工具

    百科

    去年冬天,我在一个技术论坛上看到有人发帖求助:某款售价299元的PDF编辑软件,试用期只有7天,他需要连续用三个月处理一批档案扫描件,问有没有办法“续杯”。底下跟了四十多条回复,一半在教他改系统时间, ...

    【百科】

    阅读更多


友情链接