【问题标题】:django query optimization - when to use sql and when to use pythondjango查询优化——什么时候用sql,什么时候用python
【发布时间】:2014-10-29 15:32:15
【问题描述】:

我正在寻找一个通用的经验法则,什么时候重新查询数据库更快,什么时候使用 python 从缓存中提取数据更快。

假设我需要同时从数据库中提取两件事:所有比萨饼和 pk=5 的特定比萨饼。

什么更优化:

pizzas = Pizza.objects.all()   
specific_pizza = Piazza.objects.get(pk=5)

pizzas = Pizza.objects.all()
for pizza in pizzas:
    if pizza.pk == 5
        specific_pizza = pizza
        break 

当然,这取决于数据库。比如pizza是1000万行,很明显重新查询sql比较好,如果pizza是10行,即使字段被索引,python也可能更快。

任何人都可以帮助在中间范围内进行更优化吗?比如比萨饼是几百行?数千行?

【问题讨论】:

    标签: python sql django query-optimization


    【解决方案1】:

    这个问题没有明确的答案 - 正如您所说,它取决于数据库(可能还取决于它的位置、表的数量和大小......)。您必须在您的特定环境中进行测试。

    除了原始速度之外,使用第一个版本还有一些重要的优势:

    • 更短更清晰
    • ORM 确切地知道您想要什么,因此可以在该级别进行任何进一步的优化,而不是将它们推送到您的应用程序
    • 它避免了在您的网络服务器中进行(潜在的)密集计算

    另外,值得深思的是:如果您的表足够小,python 比 DB 快,那么速度是否重要?

    您可能想了解过早优化

    【讨论】:

    • (1) 只要我知道何时使用 python 和 sql 的经验法则,提前编写首选选项并不需要我付出任何代价。 (2) 我没有太多的 sql 经验,但根据经验,每页超过 20 个查询可能会很多。 (3) 全部放在一起——数据规范化,没有python的情况下我所有的查询都使用sql,可以引导我进行20多个查询。
    • @ErezO 除非您确定行数保持在非常低的限制内,否则您不可能“提前写”。如果您确实知道会有固定的低行数,那么 SQL 可能不是最适合您的应用程序的。另请注意,在执行Pizza.objects.get(pk=5) 时不会有 20 个查询 - 只有一个。即使您需要更复杂的操作(例如连接多个表),您也应该能够只用一个查询来完成大多数事情——这就是关系数据库的全部意义所在,将此类操作推送到服务器
    • 谢谢@goncalopp ch3ka。我认为不可能将其减少为一个查询,这就是我问这个问题的原因。在我需要根据同一页面上的 几个 过滤器(例如 all_pizzas、pk=5、topping=mushrooms 等)显示比萨饼的情况下,我不知道有什么方法可以可以在一个查询中完成(如果您这样做,请告诉我)。因此,问题是什么时候最好使用 python。你和 ch3ka 基本上都说经验法则应该是始终使用 SQL,而永远不要使用 python。
    • @ErezO 如果你有时间,你应该彻底阅读 Django 的文档Making Queries。我想querysets are lazy 部分回答了你的问题。请注意,您可以使用 print myqueryset.query 打印查询集表示的 SQL
    • @goncalopp 相信我,我已经从头到尾读过很多遍了。我的意思是需要同时将多个过滤器呈现到一个 html 页面中(例如“all_pizzas”和“pizzas_with_mushrooms”和“pizza_no_5”)。在这种情况下,我只看到两种解决方案——对每个查询使用 sql,或者只使用一次 sql,其余的使用 python。这就是为什么我问何时使用 python 的原始问题。顺便说一句,我没有接受答案,因为我认为它不正确。如果是这样,Django 就不会费心改进 prefetch_related 了。
    【解决方案2】:

    例如,如果披萨有 1000 万行,很明显 重新查询 sql 更好,如果披萨是 10 行,即使 字段被索引,python可能更快。

    嗯...第一个陈述:是的。第二个说法:不确定,但也不重要。 因为当只有几个比萨饼时,下一条命令会花费相当长的时间。

    任何人都可以帮助在中间范围内更优化吗?

    我猜,不像你预期的那样,但是是的:因为我们同意当有很多比萨饼时使用.get() 会更快,并且因为我们看到只有当有很多比萨饼时性能才是一个问题,考虑到这个事实未来披萨的数量可能会增加,我认为我们可以同意使用.get() 是正确的做法。

    抛开性能不谈 - 它显然也更具可读性,所以你真的应该走这条路。

    另外,请注意,您可以使用 QuerySet 上的方法(.all() 返回 QuerySet!)来过滤您想要的内容。它的工作原理是“幕后的魔力”——因此假设是优化的,直到找到反对该假设的证据。所以你应该使用这些方法,直到你真正需要有针对性的优化。而且如果您曾经达到过这一点,您可以进行基准测试并获得可靠的答案。

    【讨论】:

    • thx @ch3ka,我评论了 goncalopp 的回答,但它是为你们俩准备的。
    【解决方案3】:

    我很欣赏@ch3ka 和@goncalopp 的回复,但我认为他们没有直接回答这个问题,所以这是我对自己的一些描述:

    底线,我发现 python 查找的点甚至与 sql 的点一样,大约是 1000 个条目:

    假设我已经查询了数据库并收到了 1000 个披萨:

    pizzas = Pizza.objects.all()
    

    我做了两个测试:

    测试1: 通过查看 pk,在 1000 个比萨饼中找到一个特定的比萨饼:

    for pizza in pizzas:
        if pizza.pk == 500
            specific_pizza = pizza
            break 
    

    耗时 0.2 毫秒

    测试2: 根据比萨的成员过滤,并创建一个新列表:

    mushroom_pizzas=[pizza for pizza in pizzas if pizza.topping==Pizza.MUSHROOM]
    

    其中 MUSHROOM 是可能的浇头的枚举。我选择了枚举,因为我认为它与索引数据库字段的比较是正确的

    耗时 0.3 毫秒

    使用 Django 调试工具栏,一个简单的索引 sql 查询所需的时间约为 0.3 毫秒。

    我确实像@goncalopp 和@ch3ka 一样认为,由于简单的索引查询已经是 0.3 毫秒,因此使用 python 进行优化真的没有意义。所以即使我事先知道条目的数量会少于1000,甚至远少于1000,我仍然会一直使用sql。

    如果我计算错误或得出错误的结论,我将不胜感激。

    【讨论】:

      猜你喜欢
      • 2012-04-05
      • 1970-01-01
      • 2011-09-28
      • 2012-08-07
      • 1970-01-01
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      相关资源
      最近更新 更多