【问题标题】:Performance: Using indexing and partitioning (PostgreSQL)性能:使用索引和分区 (PostgreSQL)
【发布时间】:2015-06-27 17:00:08
【问题描述】:

我有一个相当简单的数据库模型。我的“主”表如下所示:

| id (PK) | device_id (int) | msg_type (int) | rawdata (text) | timestamp (date+time) |

因此,每个接收到的消息都存储在此表中,包括消息类型、时间戳、发送它的设备和原始数据。

除了每个可能的 msg_type(总共大约 30 个)之外,我还有一个单独的表来存储已解析的原始数据。表“main_type1”的示例:

| id (PK) | main_id (FK) | device_id (int) | attribute_1 | attribute_2 | attribute_n |

(每个 msg_type 的结构不同,消息分布不均,这意味着有些表很长,有些表很小)。

请注意,device_id 始终包含在 rawdata 中,因此每个表都有此列。

现在是我的问题:

我曾经有过这样的查询:

select attribute_1, attribute_2 from main_type1 inner join main on main_type1.main_id = main.id where timestamp > X and timestamp < Y and main.device_id = Z

一开始一切都足够而且很快。但是现在我的数据库在“main”中有超过 400.000.000 个条目。现在查询最多需要 15 分钟。

索引

我尝试使用索引,例如:

CREATE INDEX device_id_index ON main (device_id);

好吧,现在我可以更快地从主表中检索数据,但它对连接没有帮助。我最大的问题是我只将时间戳信息存储在主表中。所以我必须一直加入......这是我的数据库模型的一般故障吗?我试图避免两次存储时间戳。

分区

一种解决方案是使用分区为每个 device_id 创建一个包含原始数据的新表吗?然后我会(当然自动)创建适当的分区,例如:

main_device_id_343223
main_device_id_4563
main_device_id_92338
main_device_id_4142315

这会给我与连接相关的速度优势吗?我还有什么其他选择?为了完整起见:我使用的是 PostgreSQL

【问题讨论】:

  • 分区不是查询性能特性,与使用良好的索引策略相比,它通常会使查询性能更差。
  • 当您的查询根本没有提到设备时,为什么要在设备上编制索引?
  • @usr:你说得对,我在查询中添加了缺少的 id。当然,我正在尝试获取特定设备的数据。感谢您指出这一点!
  • 您是否尝试过为这个特定查询创建理想的索引?每张桌子上一个。报告该配置的性能数。
  • “完美索引”是什么意思?说明有点不清楚,你能给我更多关于我应该使用哪些索引的信息吗?然后我会报告绩效率

标签: database performance postgresql indexing partitioning


【解决方案1】:

由于您的问题是join 的执行时间,首先要做的是尝试通过以下方式创建索引来加快查询速度:

  1. 帮助连接本身的索引,在这种情况下是外键 main.id 上的索引 main_type1(请注意,外键声明不会自动创建索引):

    CREATE INDEX main_type_main_id_index ON main_type1(main_id);
    
  2. 有助于限制查询所考虑的数据集的索引,在本例中是时间戳属性:

    CREATE INDEX main_timestamp_index ON main(timestamp);
    

如果您的查询仅查找值的特定子集,您还可以考虑为属性时间戳创建Partial Index

如果这些索引不能显着加快查询速度,那么您应该遵循@klin 的答案。

【讨论】:

  • 这看起来更像是评论而不是答案。如果它是一个答案,请展开它或添加更多详细信息,否则将其删除并将其添加为问题的评论。
  • 感谢@Ram 的评论,我扩展了查询,因为我认为它可以解决这个问题。
  • 感谢您扩展答案。我对其进行了编辑以改进它。
  • 感谢 Renzo 和 klin。索引有助于提高性能,现在查询大约需要。原来时间的1/10。但是,这仍然太长了。出于这个原因,我也会在不久的将来尝试使用分区
  • 好的,但是如果您更频繁地使用的时间戳是所有时间戳的(相对)小子集(例如,如果您从某个时间开始频繁查询_。
【解决方案2】:

我会建议这样的场景:首先,创建 Renzo 提出的索引。如果这还不足以提高性能,请尝试使用分区。

From the documentation:

分区可以提供几个好处:查询性能可以 在某些情况下显着改善,特别是当大多数 表中频繁访问的行位于单个分区或 少量的分区。分区替代领先 索引列,减少索引大小并使其更有可能 索引的大量使用部分适合内存。 (...)

如果您对所有包含对特定设备(例如您的问题)的引用的查询进行分区,将会快得多。 只有那些适用于许多 device_id 的查询(例如包含聚合)可能会更慢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2020-05-01
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    相关资源
    最近更新 更多