我已经为产品的Title
创建了索引。
CREATE INDEX products_title_trgm_idx
ON products USING gin(title gin_trgm_ops)
我尝试创建一个准备语句,当我使用相同的搜索值对其执行多个调用时,它会使用我的索引进行前 4 个查询,并且速度非常快,大约 20 毫秒。但第五次它只是随机决定不使用索引,这使得它执行 3-4 秒。为什么会发生这种情况?
PREPARE my_test AS SELECT "products"."id","products"."active","products"."title","products"."subtitle","products"."description","products"."isbn","products"."ean","products"."bznr","products"."cover_p
icture","products"."publication_date","products"."edition","products"."publisher","products"."stock","products"."delivery_time","products"."selling_price","products"."width","products"."height","products"."lengt
h","products"."weight" FROM "products" WHERE products.title ILIKE $1 LIMIT 10;
我创建了这个准备语句,然后做了
EXECUTE my_test('%Warum Frauen alles besser wissen - und trotzdem alles falsch machen%');
连续5次,前4次使用索引,速度超快,但第五次及之后的几次使用seq扫描,速度超慢?它为什么要这么做?我尝试禁用 seq 扫描,它会与索引一起执行并始终在 20 毫秒内执行,但我知道禁用这不是一个好主意。
最佳答案
在您的情况下,PostgreSQL 在第五次执行该语句后切换到通用计划。通常这是一个很好的举措,因为它节省了每次执行语句时规划语句的开销。它只是在你的情况下出了问题。
在前五次执行之后,PostgreSQL 会测试通用计划是否与迄今为止执行的自定义计划一样高效。你的情况似乎出了问题。因此,PostgreSQL 要么估计自定义计划太贵,要么估计通用计划太便宜。
如果没有看到两个计划的 EXPLAIN
输出,我必须猜测(从 PostgreSQL v16 开始,您可以使用 EXPLAIN (GENERIC_PLAN)
获取通用计划)。我的猜测是慢速计划使用并行顺序扫描。默认情况下,PostgreSQL 估计索引扫描相当昂贵,因为 random_page_cost
是 seq_page_cost
的四倍。如果您没有旋转磁盘,或者您的数据已缓存,则应减少 random_page_cost
来告知 PostgreSQL。这可能足以让 PostgreSQL 更喜欢索引扫描。其他可能的措施可能是将 max_parallel_workers_per_gather 设置为 0 来禁用并行查询。
最后,有一个开关可以完全禁用通用计划的生成:您可以将 plan_cache_mode
设置为 force_custom_plan
。如果其他方法都失败了,请尝试一下。
关于database - PREPARE 语句在几次调用后决定不使用索引,即使它更慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76116100/