【问题标题】:Second almost identical subquery takes much longer第二个几乎相同的子查询需要更长的时间
【发布时间】:2016-05-10 18:45:53
【问题描述】:

我在一个包含大约 18mio 条目的路由数据库上执行带有两个几乎相同的子查询的 SQL 查询:

EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT source.source, target.target FROM
    (SELECT source FROM at_2po_4pgr WHERE osm_source_id=380253639 LIMIT 1) as source,
    (SELECT target FROM at_2po_4pgr WHERE osm_target_id=373850046 LIMIT 1) as target

解释分析返回以下内容:

Nested Loop  (cost=0.00..491634.63 rows=1 width=8) (actual time=6437.767..6437.768 rows=1 loops=1)
   Output: at_2po_4pgr.source, at_2po_4pgr_1.target
   Buffers: shared hit=6136 read=1684402
   ->  Limit  (cost=0.00..215090.14 rows=1 width=4) (actual time=6437.740..6437.740 rows=1 loops=1)
         Output: at_2po_4pgr.source
         Buffers: shared hit=6132 read=1684402
         ->  Seq Scan on public.at_2po_4pgr  (cost=0.00..1935811.25 rows=9 width=4) (actual time=6437.738..6437.738 rows=1 loops=1)
               Output: at_2po_4pgr.source
               Filter: (at_2po_4pgr.osm_source_id = 380253639)
               Rows Removed by Filter: 17052688
               Buffers: shared hit=6132 read=1684402
   ->  Limit  (cost=0.00..276544.46 rows=1 width=4) (actual time=0.020..0.020 rows=1 loops=1)
         Output: at_2po_4pgr_1.target
         Buffers: shared hit=4
         ->  Seq Scan on public.at_2po_4pgr at_2po_4pgr_1  (cost=0.00..1935811.25 rows=7 width=4) (actual time=0.020..0.020 rows=1 loops=1)
               Output: at_2po_4pgr_1.target
               Filter: (at_2po_4pgr_1.osm_target_id = 373850046)
               Rows Removed by Filter: 94
               Buffers: shared hit=4
 Planning time: 0.109 ms
 Execution time: 6437.887 ms

在这种情况下,第一个子查询大约需要 6500 毫秒,而第二个子查询只需要 0.02 毫秒!有时情况正好相反,因此第二个查询是慢查询。当我将查询作为单个查询运行时,它们会在 10 毫秒内返回。所以我假设没有为执行这两个查询提供足够的缓冲内存,但是我已经将大部分默认值增加了很多。

我当前的 postgresql 内存设置是:

# - Memory -

shared_buffers = 12GB                   # min 128kB
                                        # (change requires restart)
#huge_pages = try                       # on, off, or try
                                        # (change requires restart)
temp_buffers = 64MB                     # min 800kB
#max_prepared_transactions = 0          # zero disables the feature
                                        # (change requires restart)
# Note:  Increasing max_prepared_transactions costs ~600 bytes of shared memory
# per transaction slot, plus lock space (see max_locks_per_transaction).
# It is not advisable to set max_prepared_transactions nonzero unless you
# actively intend to use prepared transactions.
work_mem = 256MB                                # min 64kB
maintenance_work_mem = 512MB            # min 1MB
#autovacuum_work_mem = -1               # min 1MB, or -1 to use maintenance_work_mem
#max_stack_depth = 2MB                  # min 100kB
dynamic_shared_memory_type = posix      # the default is the first option
                                        # supported by the operating system:
                                        #   posix
                                        #   sysv
                                        #   windows
                                        #   mmap
                                        # use none to disable dynamic shared memory

所以我完全不知道这些不同的执行时间的原因。

【问题讨论】:

  • 似乎 select limit 1 与“让我找到满足条件 xyz 的第一行”不同,而是在删除后检索所有满足条件的行的常规查询全部 - 1

标签: sql postgresql


【解决方案1】:

不知道为什么你有不同的时间。我的猜测是第一个扫描表,第二个利用一些缓存,因此花费的时间更少。

尝试颠倒查询的顺序,看看是否有相似的结果或时间变化

EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT source.source, target.target FROM        
    (SELECT target FROM at_2po_4pgr WHERE osm_target_id=373850046 LIMIT 1) as target,
    (SELECT source FROM at_2po_4pgr WHERE osm_source_id=380253639 LIMIT 1) as source

顺便说一句:您应该为target 创建一个索引,为source 创建一个索引。正如您在EXPLAIN 上看到的,查询正在执行SEQ SCAN

编辑:在看到 EXPLAIN 消息 Rows Removed by Filter: 17052688Rows Removed by Filter: 94 之后,target 可能会更快出现在搜索中,limit 1 停止搜索看起来更快。尝试使用不同的 ID 值 这是您应该创建一个索引的另一个原因。

【讨论】:

  • 创建索引完成了这项工作。起初我想知道,因为我假设我已经创建了它们,但是表在内部使用不同的 id 来表示具有索引的源和目标,但是没有 osm id 的索引。
  • 是的,索引应该是osm_source_idosm_target_id my bad
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-18
  • 2019-10-30
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 2019-11-25
  • 1970-01-01
相关资源
最近更新 更多