【问题标题】:Consistently getting postgres query plan for specific query to use index rather than scan一致地为特定查询获取 postgres 查询计划以使用索引而不是扫描
【发布时间】:2013-09-14 21:47:55
【问题描述】:

一段时间以来,我一直在努力弄清楚如何让查询计划变得更聪明,但现在非常不成功。我已经搞砸了 work_mem 和朋友,大量运行 vacumm analyze 并尝试使用 order by 更改查询。我已经包含了 3 次具有不同偏移量的相同查询。我的印象是这个查询几乎没有它可能的性能。有什么想法吗?

以防万一它没有跳出来 - 以下查询之间的唯一变化是offset

bloomapi=# explain analyze SELECT * FROM npis WHERE provider_last_name_legal_name = 'THOMPSON' offset 250 limit 10;
                                                                             QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=965.13..998.97 rows=10 width=2589) (actual time=568.458..577.507 rows=10 loops=1)
   ->  Bitmap Heap Scan on npis  (cost=119.15..20382.11 rows=5988 width=2589) (actual time=58.140..577.027 rows=260 loops=1)
         Recheck Cond: ((provider_last_name_legal_name)::text = 'THOMPSON'::text)
         ->  Bitmap Index Scan on npis_temp_provider_last_name_legal_name_idx1  (cost=0.00..117.65 rows=5988 width=0) (actual time=36.819..36.819 rows=5423 loops=1)
               Index Cond: ((provider_last_name_legal_name)::text = 'THOMPSON'::text)
 Total runtime: 578.301 ms
(6 rows)

bloomapi=# explain analyze SELECT * FROM npis WHERE provider_last_name_legal_name = 'THOMPSON' offset 100 limit 10;
                                                                             QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=395.81..435.40 rows=10 width=2589) (actual time=0.397..0.440 rows=10 loops=1)
   ->  Index Scan using npis_temp_provider_last_name_legal_name_idx1 on npis  (cost=0.00..23701.38 rows=5988 width=2589) (actual time=0.063..0.293 rows=110 loops=1)
         Index Cond: ((provider_last_name_legal_name)::text = 'THOMPSON'::text)
 Total runtime: 0.952 ms
(4 rows)

bloomapi=# explain analyze SELECT * FROM npis WHERE provider_last_name_legal_name = 'THOMPSON' offset 4100 limit 10;
                                                                            QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=13993.25..14027.09 rows=10 width=2589) (actual time=9356.723..9400.021 rows=10 loops=1)
   ->  Bitmap Heap Scan on npis  (cost=119.15..20382.11 rows=5988 width=2589) (actual time=2.968..9393.327 rows=4110 loops=1)
         Recheck Cond: ((provider_last_name_legal_name)::text = 'THOMPSON'::text)
         ->  Bitmap Index Scan on npis_temp_provider_last_name_legal_name_idx1  (cost=0.00..117.65 rows=5988 width=0) (actual time=1.943..1.943 rows=5423 loops=1)
               Index Cond: ((provider_last_name_legal_name)::text = 'THOMPSON'::text)
 Total runtime: 9400.426 ms
(6 rows)

一些相关说明:

  • 我在运行第一个查询之前清除了系统上的共享内存,因此第一个查询的某些实际时间可能会受到索引加载的影响
  • 数据宽而稀疏 -- 329 列,其中许多是空字符变化 (30ish)
  • 数据实际上是只读的 - 每周更新 15k 行。
  • 当 ubuntu ppa 附带默认数据库设置时,这些查询的性能实际上更高除此以外)。已从默认值更改的参数:shared_buffers = 256MB, Effective_cache_size = 512MB, checkpoint_segments = 64, checkpoint_completion_target = 0.9, default_statistics_target = 500
  • 表本身的实际数据约为 400 万行/1.29GB,provider_last_name_legal_name 是 btree 索引的——索引大小为 95mb。大约 3/4 的行在该列中有一个非空值,整个表有 488k 个不同的值

【问题讨论】:

  • 您是否尝试将random_page_cost 设置为较低的值(~ 1.5)?顺便说一句:work_mem 的设置是什么加上:effective_cache_size = 512M 似乎相当低;您的 1.3GB 表应该(几乎)适合核心,至少是索引。
  • 顺便说一句:我不喜欢没有 ORDER BY 的 LIMIT/OFFSET。在似乎也被索引的文本列上。 provider_last_name_legal_name 的基数是多少?最后:1.2G size/4Mrows := 300 bytes byte/row,这似乎有点高。顺便说一句:您如何将 329 列放入 300 字节中?
  • @wildplasser 将 random_page_cost 设置得较低确实会使规划器估计索引扫描对于更高的偏移量更快,但规划器仍然会在 random_page_cost = 1.5 的偏移量 700 左右切换。这就是说,即使索引扫描性能似乎也会受到很大的偏移。将 329 列拟合为 300 个字节——大多数列为空/表非常稀疏。
  • @wildplasser 此外,基数不是超高/超低——4M 行中有 3M 有 488k 个不同的值(最后 1M 行是空的)。这是一张美国姓氏的表格——所以它的频率分布可能类似于names.mongabay.com/most_common_surnames.htm
  • 我知道幂律分布。但坏消息是,鉴于 300 多列,您可能会遇到数据建模问题。 (就我个人而言,我什至无法想象 300 多个列是完全独立/正交的。这种事情可能发生在高等数学中。甚至在物理学中也不会)

标签: sql database performance postgresql database-performance


【解决方案1】:

我有根据的猜测是,大量的偏移量正在触发这些计划。即使您将结果限制为十行,PostgreSQL 也必须考虑所有前面的行。我怀疑当您删除 offset(例如,在第一个查询中使用 limit 260)时,您会看到类似的运行时。

您可以使用configuration parameters 禁用某些计划类型,直到查询共享相似的计划。这可以帮助您了解为什么一个计划比另一个更好。

set enable_bitmapscan = false;

【讨论】:

  • 谢谢!虽然这并没有解决我的性能问题,但它确实回答了我的问题/帮助我调试并发现正在使用的查询计划并不是那么愚蠢。具有高偏移量的索引扫描也很慢。在实际切换正确的情况下,偏移量要高得多——但偏移量似乎只是一般的低性能操作(请参阅 Tom Lane-2 在postgresql.1045698.n5.nabble.com/… 上的回复)。我可能需要找到一种更有创意的查询方式,或者对此类查询的低性能表示满意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-24
  • 2011-04-22
  • 2018-05-05
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多