【问题标题】:Postgres prefers wrong index in simple queryPostgres 在简单查询中更喜欢错误的索引
【发布时间】:2021-08-26 20:14:48
【问题描述】:

my_table 包括:

user_id                | character varying           |           | not null |
epic_id                | text                        |           | not null |

"IDX_user" UNIQUE, btree ("user_id") WHERE status < 101
"IDX_epic" UNIQUE, btree ("epic_id") WHERE status < 101 

有问题的查询

EXPLAIN ANALYZE SELECT * FROM my_table WHERE "epic_id" = 'asdf' and "status" < 101 LIMIT 1;

 Limit  (cost=0.28..8.29 rows=1 width=276) (actual time=0.230..0.231 rows=0 loops=1)
   ->  Index Scan using "IDX_user" on my_table  (cost=0.28..8.29 rows=1 width=276) (actual time=0.229..0.230 rows=0 loops=1)
         Filter: ("epic_id" = 'asdf'::text)
         Rows Removed by Filter: 273
 Planning Time: 0.122 ms
 Execution Time: 0.248 ms

有一个非常好的IDX_epic。为什么我们要使用 IDX_user,遍历 100 行,并且在事务中使用它时可能会导致烦人的锁?

有趣的花絮

  • SET random_page_cost=1 没有帮助,正如其他 stackoverflow 帖子所推荐的那样
  • 在本地,它使用正确的索引!本地只有 90 行 status &lt; 101
  • 在执行"epic_id" = table.random_column 的内部连接时,计划确实使用IDX_epic
  • "user_id""epic_id" 是不同的类型,但据我所知,textcharacter varying 之间的差异接近于 0。
  • 根据pg_stat_all_indexesIDX_epicidx_scan 为 9,这证实它除了我的测试外没有被使用。

【问题讨论】:

  • 你先运行VACUUM ANALYZE了吗?
  • 您最近是否对生产表进行过分析(或真空分析)?
  • 终于修好了,谢谢>。

标签: postgresql indexing


【解决方案1】:

为什么 epicId 在引号内,而 status 不在? 你也应该像epicId LIKE 'asdf'一样使用LIKE来比较列值和字符串。

【讨论】:

  • Postgres 不区分大小写,因此它将不带引号的 epicId 转换为 epicid 并且找不到该列。 LIKE 仍然使用错误的索引。
  • 对我来说似乎更容易让您的列名遵循蛇形命名约定并重试
  • 好的,现在是蛇盒。
【解决方案2】:

VACUUM ANALYZE 解决了这个问题 -- 单独ANALYZE 可能会解决它。

【讨论】:

    猜你喜欢
    • 2017-09-07
    • 2012-06-19
    • 1970-01-01
    • 2015-04-22
    • 1970-01-01
    • 2015-04-03
    • 2014-03-30
    • 2012-12-23
    • 2012-09-18
    相关资源
    最近更新 更多