【问题标题】:Best indexing alternative to speed up querying my millions of data in PostgreSQLPostgresql 查询耗时超过 5 分钟
【发布时间】:2020-07-07 04:17:51
【问题描述】:

我有一个包含超过 5 亿行的大表。我正在尝试找到最好的索引替代方法来加快查询时间。我想根据时间戳排序会大大减慢查询时间。该表有 15 列。

MyTable 与 other_table 有 @ManyToOne 关系。用户也可以定义最大结果。代码如下所示:

// Im showing the query itself here instead of the name of @NamedQuery inside the entity class.
TypedQuery<MyTable> query = em.createNamedQuery("SELECT m FROM my_table m WHERE m.other_table.id = :id AND m.city in :cities ORDER BY m.timestamp DESC", MyTable.class);
query.setParameter("id", id);
query.setParameter("cities", cities);
query.setMaxResults(number);
return query.getResultList();

这种查询的最佳选择是什么?综合指数?哪种索引类型最适合这种情况?

我们有这样的索引,但正如我所说,这需要很长时间。

CREATE INDEX my_table_idx ON my_schema.my_table USING btree (other_table_id, timestamp DESC NULLS LAST, city)

编辑:

这是执行计划:

Limit  (cost=2876886.98..2876887.03 rows=20 width=162) (actual time=101820.279..101820.284 rows=20 loops=1)
  Buffers: shared hit=8063 read=635649 written=12198
  ->  Sort  (cost=2876886.98..2879114.34 rows=890941 width=162) (actual time=101820.277..101820.278 rows=20 loops=1)
        Sort Key: timestamp DESC
        Sort Method: top-N heapsort  Memory: 35kB
        Buffers: shared hit=8063 read=635649 written=12198
  ->  Bitmap Heap Scan on my_table  (cost=31640.64..2853179.36 rows=890941 width=162) (actual time=199.824..101221.260 rows=711774 loops=1)
        Recheck Cond: ((m_other_table_id = '14b713d5-fb1a-4dbd-c013-fat4a7f6c8e3'::uuid) AND (m_city_id = 3))
        Rows Removed by Index Recheck: 28920837
        Heap Blocks: exact=23535 lossy=615808
        Buffers: shared hit=8060 read=635649 written=12198
        ->  Bitmap Index Scan on my_table_idx  (cost=0.00..31417.90 rows=890941 width=0) (actual time=189.011..189.012 rows=711777 loops=1)
              Index Cond: ((m_other_table_id = '14b713d5-fb1a-4dbd-c013-fat4a7f6c8e3'::uuid) AND (m_city_id = 3))
              Buffers: shared hit=90 read=4276
Planning time: 0.198 ms
Execution time: 101821.109 ms

这些是我们拥有的索引。

CREATE INDEX my_table_idx ON my_schema.my_table USING btree (other_table_id, timestamp DESC NULLS LAST, city)
CREATE UNIQUE INDEX my_table_prev_id_idx ON my_schema.my_table USING btree (m_prev_id)
CREATE INDEX my_table_other_table_fk_idx ON my_schema.my_table USING btree (m_other_table_id)
CREATE UNIQUE INDEX my_table_pkey ON my_schema.my_table USING btree (m_id)
CREATE INDEX my_table_track_fk_idx ON my_schema.my_table USING btree (m_track_id)

编辑 2:

我想知道为什么并行工作者没有出现在我的执行计划中。我已经配置了这些设置。

max_worker_processes = 6;
max_parallel_workers = 6;
max_parallel_workers_per_gather = 3;

【问题讨论】:

  • @a_horse_with_no_name 我更新了我的问题。我希望我能按照你的要求做到。
  • 您的work_mem 似乎太小而无法有效地处理位图索引扫描(这就是您有这么多有损堆块的原因)。您可以尝试大幅增加它,看看这是否会提高性能。将my_table_idx 的定义更改为(other_table_id, city, timestamp) 也可能会有所帮助(其中的时间戳列无论如何都没有帮助)
  • @a_horse_with_no_name 你认为btree 是这种数据的最佳索引类型吗?
  • 您提供了一些很好的信息。但是缺少要点:Postgres 版本、表定义(CREATE TABLE 语句)。考虑这里的说明:stackoverflow.com/tags/postgresql-performance/info

标签: sql postgresql indexing named-query postgresql-performance


【解决方案1】:

您需要检索 1/2 亿个元组吗?我怀疑。

也许问题是:您是否打算在您的程序中处理此结果以执行其他操作?也许您可以将这项工作推送到 DBMS,这样您就只会收到您需要的元组。

关于您的查询。我认为问题在于您按一个属性进行连接,并按另一个属性进行排序。

编辑:我看了你的解释。解释有一个限制。您的查询没有。

所以你要加入每一个元组以找到具有最大时间戳的元组?

执行以下操作:

使用子查询编写查询,您可以在其中检索不同的时间戳,对它们进行排序并保持 N 是最新的。

然后搜索具有此时间戳的连接元组。像这样的:

select * from a join b on (whetever join condition) where timestamp IN (select distinct timestamp from ... order by timestamp desc limit 100)

【讨论】:

    【解决方案2】:

    根据计划中的这条线:

    Cond: ((m_other_table_id = '14b713d5-fb1a-4dbd-c013-fat4a7f6c8e3'::uuid) AND (m_city_id = 3))
    

    你的理想索引应该是(m_other_table_id, m_city_id)。不是other_table_id,不是city。您显示的计划与查询并不真正匹配,因此很难说出拼写错误的位置 - 在显示的计划或显示的查询中。

    另外,由于您是通过timestamp 订购的,我们可以将其添加到索引中。

    所以,我会尝试以下索引:

    CREATE INDEX idx ON my_schema.my_table USING btree 
        (m_other_table_id, m_city_id, timestamp DESC)
    

    这里的列顺序很重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-12
      • 2012-11-04
      • 2014-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多