【问题标题】:Do the results of a SQL query explain depend on the size of the database?SQL 查询的结果是否取决于数据库的大小?
【发布时间】:2012-09-01 01:54:01
【问题描述】:

我的应用程序在 Hibernate 中使用 JPA,我看到 hibernate 在我的日志文件中生成了一些有趣的 SQL 查询,其中包含很多连接。该应用程序现在没有很多用户,我担心当数据库规模增长时,hibernate 生成的一些查询会导致问题。

我已经通过 EXPLAIN 命令运行了一些由 hibernate 生成的 sql 查询,以查看生成的查询计划。

  1. EXPLAIN 的输出是否取决于数据库的大小?当我的数据库变大时,查询计划器会为相同的 SQL 查询生成不同的计划吗?

  2. 我应该在开发/部署周期的哪个阶段查看由 hibernate 生成的 sql 查询的 SQL 查询计划?什么时候使用 EXPLAIN 合适。

  3. 当数据库非常小以至于每个查询(无论看起来多么复杂)都在 0.5 秒内运行时,如何使用 explain 的输出来确定查询是否会成为问题?

我使用 Postgres 9.1 作为我的应用程序的数据库,但我对上述问题的一般答案很感兴趣。

【问题讨论】:

  • 智能数据库使用统计来帮助对如何创建计划做出有根据的猜测。这些统计数据可能会随着新数据的变化而变化。确切的范围、收集、提示等是非常特定于数据库的。但是,这 [很可能] 现在不用担心 :) 只需专注于创建一个干净的模型。
  • @pst 那么这是否意味着当数据库仍然很小时使用解释是没有意义的。
  • 请注意,对于早于即将发布的 9.2 的 PostgreSQL 版本,您应该 PREPARE 一个语句然后 EXPLAIN EXECUTE 它以匹配 Hibernate 将如何执行您的语句。在 9.1 及以下版本中,prepared- 和 non-prepared 语句中的查询计划可能不同。
  • @pst:在具有基于成本的优化器(如 PostgreSQL)的数据库中,用于其中行数很少的表的索引不一定与行数很多时相同它。随着表格的增长,计划者可能会选择非常不同的计划。

标签: mysql sql sql-server oracle postgresql


【解决方案1】:

实际上,@ams 你的评论是对的——用少量数据解释通常是没有意义的。

如果一个表只有 10 行,那么它很可能都在一个页面中,并且读取一行的成本(大致)与所有 10 行相同。首先访问索引然后获取页面将比仅读取更昂贵阅读大量并忽略你不想要的东西。 PostgreSQL 的规划器有configured costs 用于索引读取、表读取、磁盘访问与缓存访问、排序等。它根据表的(近似)大小和其中的distribution of values 调整这些大小。它不做的(截至待定的 9.2 版本)是考虑跨列或跨表相关性。它也不提供手动提示,让您覆盖规划器的选择(与 MS-SQL 或 Oracle 不同)。

每个 RDBMS 的规划器都有不同的优势和劣势,但我认为可以公平地说 MySQL 是最弱的(尤其是在旧版本中)。

所以 - 如果您想知道您的系统在 100 个并发用户和数十亿行的情况下如何运行,您需要生成测试数据并加载其中相当一部分。更糟糕的是,您还希望拥有大致相同的值分布。如果大多数客户有大约 10 张发票,但少数有 1000 张发票,那么这就是您的测试数据需要反映的内容。如果您需要跨多个 RDBMS 保持性能,请在所有 RDBMS 上重复测试。

这当然与系统的整体性能是分开的,这取决于您的服务器的大小和功能与其所需的负载。一个系统可以应对负载的稳定增长,然后你会突然发现性能会随着缓存大小的超出而迅速下降等等。

HTH

【讨论】:

    【解决方案2】:

    1 EXPLAIN 的输出是否取决于数据库的大小?当我的数据库大小增加时,查询计划程序会生成 相同 SQL 查询的不同计划?

    这完全取决于您的数据和有关数据的统计信息。当有人忘记分析或关闭 auto_vacuum(包括分析)时,由于缺乏统计信息,会出现许多性能问题。

    2 在开发/部署周期的哪个阶段,我应该查看由 hibernate 生成的 sql 查询的 SQL 查询计划? 什么时候使用 EXPLAIN 合适。

    Hibernate 有向数据库发送大量查询的习惯,即使对于简单的连接也是如此。打开你的查询日志,并留意那个。稍后,您可以对日志中的所有查询运行自动解释。

    3 当数据库非常小以至于每个查询时,如何使用 explain 的输出来确定查询是否会成为问题 无论看起来多么复杂,都可以在 0.5 秒内运行?

    不,因为这完全取决于数据。当 95% 的用户是男性时,搜索男性时不会使用性别索引。当你在寻找一个女人时,这个索引是有意义的并且会被使用。对性别 = 女性的记录进行功能索引甚至更好:索引永远不会从索引中受益的东西是没有用的,索引会小得多。

    您可以做的唯一事情是预测索引的使用情况,使用set enable_seqscan = off; 进行测试,这将表明可以使用某些索引,但仅此而已。

    【讨论】:

    • s/功能指标/部分指标/g ?
    • Frank 像往常一样完全正确,而且@ams 认为并非所有查询都受益于或应该使用索引。如果您要连接两个没有任何过滤器的中小型表,那么 seqscan 和 mergejoin 可能是最好的计划。
    • 当然,如果语句是 prepared 在服务器端,它必须使用 generic 计划而不是基于使用的参数的计划每次运行;因此,您可能无法按照所述优化性别示例。请参阅 PostgreSQL JDBC 驱动程序的 prepareThreshold 选项。
    • 所以基本上现在索引我的一些表还为时过早,因为我不知道数据分布。
    • @kgrittn preapreThreshold 设置可以看看stackoverflow.com/q/11290960/438319 或许你知道问题的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2010-12-29
    • 2020-10-01
    • 1970-01-01
    相关资源
    最近更新 更多