【问题标题】:Under what conditions would SELECT by PRIMARY KEY be slow?在什么情况下 SELECT by PRIMARY KEY 会很慢?
【发布时间】:2011-03-22 06:35:54
【问题描述】:

在一个相当典型的 EclipseLink/JPA 应用程序中解决一些数据库性能问题。

我看到频繁的查询需要 25-100 毫秒。这些是简单的查询,只需从表中选择其主键等于一个值的所有列。他们不应该很慢。

我正在使用 log_min_duration_statement 查看 postgres 日志中的查询时间,因此这应该可以消除任何网络或应用程序开销。

这个查询并不慢,但经常使用。

为什么按主键选择 * 会很慢? 这是 postgres 特有的还是一般的数据库问题? 我怎样才能加快速度?一般来说?对于 postgres?

pg 日志中的示例查询:

2010-07-28 08:19:08 PDT - LOG:  duration: 61.405 ms  statement: EXECUTE <unnamed>  [PREPARE:  SELECT coded_ele
ment_key, code_system, code_system_label, description, label, code, concept_key, alternate_code_key FROM coded
_element WHERE (coded_element_key = $1)]

表格有大约 350 万行。

我还对这个查询运行了 EXPLAIN 和 EXPLAIN ANALYZE,它只进行索引扫描。

【问题讨论】:

  • 数据集有多大?每行有多大?查询是什么样的?
  • 您是否对数据库进行了集群化?您在发布之前是否进行了真空全面分析?什么Pg版本?
  • 没有集群,也不是一个真正的选择。我还没有进行真空全面分析(我会),这是 PG 8.1。
  • 你应该做全真空。如果你没有定期清理你的数据库,你应该添加一个 cron 作业来做到这一点。

标签: sql database jpa performance eclipselink


【解决方案1】:

select * 几乎总是一个非常非常糟糕的主意。

  1. 如果字段的顺序发生变化,它会破坏你的代码。 根据 cmets 的说法,鉴于您使用的抽象库,这并不重要。
  2. 您从表中返回的数据可能比实际需要的多。选择您想要的特定字段可以节省传输时间。

25ms 大约是您在几乎所有类型的 SQL 查询中都会看到的下限——这只是两次磁盘访问!您可能想研究减少查询运行次数的方法,而不是尝试优化查询。

【讨论】:

  • 我真希望人们在投反对票时会发疯!
  • @Billy,您在两个帐户中错了:1.除非您删除表格,否则字段顺序不会更改。 PK的25ms是很长的时间。然而,这不是投反对票的原因。您没有回答问题,即如何解决问题,而不是您在 25 毫秒内获得了多少随机磁盘访问。
  • @jmz:ALTER 也可以更改字段顺序。至于问题,我相信是Why would selecting * by primary key be slow?,然后是How can I speed this up?,在这种情况下,我看不出这不能回答问题。
  • @Pascal:我没有使用 JPA 的经验;通常仅适用于 RDBMS。如果您能在此处指出 JPA 如何改变游戏规则,我将删除答案。
  • @Billy 道歉,我真的很想删除我的评论,它只是一个无用的。删除期间似乎出了点问题(可能是我)。无论如何,要回答您的问题,JPQL 查询 SELECT * FROM MyEntity 将被转换为 SELECT somealias.field1, ..., somealias.fieldN from MyEntityTable somealias SQL 查询,因此字段的顺序实际上根本不是问题(第一个要点)。关于第二个,我想知道它是否适用,因为 OP 使用的是log_min_duration_statement。这是我应该写的第一条评论。
【解决方案2】:

该行异常大或包含 BLOB 和大型二进制字段?

这是直接通过控制台还是通过一些数据访问 API(如 jdbc 或 ADO.NET)运行此查询?您提到了看起来像数据访问 API 的 JPA。对于短查询,数据访问 API 占执行时间的很大一部分——创建命令、创建对象来保存行和单元格等。

【讨论】:

  • 这些查询速度是从 postgres 日志中记录的,因此它是实际查询时间,而不是数据 API (JPA) 时间。
【解决方案3】:

选择 * 会使您的数据库更努力地工作,并且作为一般规则,这是一种不好的做法。在 stackoverflow 上有很多关于这个的问题/答案。

您是否尝试将 * 替换为字段名称?

【讨论】:

  • JPA 会根据您使用字段名称的描述生成查询。为简洁起见,我将其描述为“Select *”。
  • 啊——那你不应该得到那个 :-) 还有一百万种其他的东西会影响性能...压缩表或重建索引会有所帮助,将索引填充设置为更利于阅读而不是写入、分区(是否在较慢的驱动器上)、计算列、更改 SELECT 中的字段顺序(为什么???我仍然不知道)等等。
  • 接受主要是为了后续评论,而不是最初的答案。给了我一份需要理解和检查的清单,以加快查询速度。
  • 我很想知道您最终发现/实施哪些解决方案最有帮助。
【解决方案4】:

好吧,我对 postgres SQL 了解不多,所以我会给你一个可能适用的 MS SQL Server 的提示。

MS SQL Server 有一个“簇索引”的概念,它是磁盘上数据的物理布局。最好在您将寻求值之间的范围(主要是日期字段)的字段上使用。如果您正在寻找一个确切的值(如主键查找),它并没有多大用处。但是,有时主键索引被无意中设置为聚集索引。这使得索引查找成为表扫描。

【讨论】:

  • 对主键使用聚集索引如何将主键上的索引查找变成表扫描?
  • 因为表是索引。因此“索引扫描”==“表扫描”
  • 但是索引查找不会是索引扫描,除非我的术语搞砸了。
  • "索引查找" = "扫描索引,使用info直接跳转到表中的位置"
【解决方案5】:

您会遇到某种锁定争用吗?您在执行这些查询时使用了哪种锁?

【讨论】:

  • 我不确定。有什么方法可以让 PG 或 JPA 告诉我何时发出锁?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2019-08-01
  • 1970-01-01
  • 2020-11-28
  • 1970-01-01
  • 2012-06-02
相关资源
最近更新 更多