【问题标题】:Overhead of a Round-trip to MySql?往返 MySql 的开销?
【发布时间】:2010-12-13 22:14:26
【问题描述】:

所以我已经构建 django 应用程序有一段时间了,喝着凉快的饮料等等:只使用 ORM,从不编写自定义 SQL。

一旦您拥有大量用户特定内容(即照片、朋友、其他数据等),网站的主页(用户将花费 80% - 90% 时间的主界面)会变得很慢

所以我打开了 sql 记录器(预装了 pinax,我只是在设置中启用了它)并想象当它报告超过 500 个数据库查询时我会感到惊讶!使用手工编码的 sql,我几乎不会在最复杂的页面上运行超过 50 个。

事后看来,这并不令人惊讶,但这似乎不太好。

...即使只有十几个查询需要 1ms+

所以我想知道,往返 mysql 有多少开销? django 和 mysql 在同一台服务器上运行,因此不应该有任何与网络相关的开销。

【问题讨论】:

  • 500 是对一页进行多次查询的方式。我们的主页有我们网站的最多查询(我认为),即 57 个查询。但其中有 52 个使用 memcached 进行缓存。
  • @Echo 我绝对同意
  • 出于好奇,您如何计算查询次数?

标签: python mysql django overhead


【解决方案1】:

数据库调用总是存在开销,在您的情况下,开销并没有那么糟糕,因为应用程序和数据库位于同一台机器上,因此没有网络延迟,但仍然有很大的成本.

当您向数据库发出请求时,它必须通过执行许多操作来准备为该请求提供服务,包括:

  • 将资源(内存缓冲区、临时表等)分配给将处理请求的数据库服务器连接/线程,
  • 反序列化 sql 和参数(即使在一台机器上也是必要的,因为这是一个进程间请求,除非您使用的是嵌入式数据库)
  • 如果不优化,则检查查询是否存在于查询缓存中并将其放入缓存中。
    • 另请注意,如果您的查询没有参数化(即值没有与 SQL 分离),这可能会导致语句的缓存未命中,这意味着每个请求都会导致每个请求都导致查询被分析和优化时间。
  • 处理查询。
  • 准备结果并将结果返回给客户。

这只是对大多数数据库管理系统为处理 SQL 请求所做的各种事情的概述。即使查询本身运行得相对较快,您也会产生 500 次开销。甚至与本地数据库的底线数据库交互也没有您想象的那么便宜。

【讨论】:

    【解决方案2】:

    每个查询的开销只是图片的一部分。您的 Django 和 Mysql 服务器之间的实际往返时间可能非常短,因为您的大多数查询都在不到一毫秒的时间内返回。更大的问题是向您的数据库发出的查询数量会很快使其不堪重负。一个页面的 500 个查询已经很多了,甚至 50 个对我来说似乎也很多。如果有 10 个用户查看复杂的页面,您现在的查询数将达到 5000 个。

    当调用者从广域网访问数据库时,到数据库服务器的往返时间更多是一个因素,其中往返时间很容易在 20 毫秒到 100 毫秒之间。

    我肯定会考虑使用某种缓存。

    【讨论】:

      【解决方案3】:

      有一些方法可以减少查询量。

      1. 使用.filter().all()得到一堆东西;在视图功能(或模板通过{%if%})中挑选和选择。 Python 可以比 MySQL 更快地处理一批行。

        “但我可以向模板发送太多”。没错,但您将执行更少的 SQL 请求。测量看看哪个更好。

        这是您在编写 SQL 时经常做的事情。这没有错——它不会破坏 ORM——但它优化了底层数据库工作并将处理放入视图函数和模板中。

      2. 避免在模板中进行查询导航。当您执行 {{foo.bar.baz.quux}} 时,SQL 用于获取与foo 关联的bar,然后是与bar 关联的baz,然后是与@ 关联的quux 987654329@。您可以通过一些谨慎的.filter() 和 Python 处理来减少此查询业务,以便在视图函数中组装一个有用的元组。

        同样,这是您在手工编写 SQL 时经常做的事情。在这种情况下,您在视图函数中收集更大批量的 ORM 管理的对象,并在 Python 中进行过滤,而不是通过大量单独的 ORM 请求。

        这不会破坏 ORM。它将使用配置文件从大量的小查询更改为几个更大的查询。

      【讨论】:

        【解决方案4】:

        仅仅因为您使用的是 ORM 并不意味着您不应该进行性能调优。

        与您一样,我有一个性能低下的应用程序的主页。我看到我正在执行数百个查询来显示该页面。我查看了我的代码,并意识到通过仔细使用select_related(),我的查询会带来更多我需要的数据——我的查询从数百个增加到了数十个。

        您还可以运行 SQL 分析器,看看是否没有索引可以帮助您最常见的查询 - 您知道,标准数据库的东西。

        缓存也是你的朋友,我想。如果很多页面没有变化,是否需要每次都查询数据库?

        如果一切都失败了,请记住:ORM 很棒,是的 - 你应该尝试使用它,因为它是 Django 哲学; 但你没有结婚

        如果您确实有一个用例,其中研究和调整 ORM 导航没有帮助,如果您确定使用标准查询可以做得更好:在这种情况下使用原始 sql。

        【讨论】:

          猜你喜欢
          • 2019-04-11
          • 2016-10-27
          • 1970-01-01
          • 2014-03-08
          • 2021-05-27
          • 2015-04-02
          • 1970-01-01
          • 1970-01-01
          • 2023-03-18
          相关资源
          最近更新 更多