PostgreSQL多表联合视图的查询计划器非最优执行计划问题
PostgreSQL多租户工作区Schema视图性能优化问题
数据库结构说明
我们的PostgreSQL数据库按租户和工作区划分多个Schema,结构如下:
reports/tenant1/workspace1 reports/tenant1/workspace2 reports/tenant2/workspace1 reports/tenant3/workspace1 reports/tenant3/workspace2 reports/tenant3/workspace3
每个工作区Schema包含结构完全一致的表集合,且每张表都包含_tenant和_workspace列,值与所在Schema的租户、工作区一一对应(例如reports/tenant1/workspace1下的表,这两列值为tenant1和workspace1)。
视图定义方式
在public Schema中,我们为每个表创建了对应的视图,用于联合所有工作区Schema中同结构的表。以example_table对应的example_view为例,视图定义如下:
SELECT _tenant, _workspace, column1, column2, column3 FROM "reports/tenant1/workspace1".example_table WHERE _tenant = 'tenant1' AND _workspace = 'workspace1' UNION ALL SELECT _tenant, _workspace, column1, column2, column3 FROM "reports/tenant1/workspace2".example_table WHERE _tenant = 'tenant1' AND _workspace = 'workspace2' UNION ALL SELECT _tenant, _workspace, column1, column2, column3 FROM "reports/tenant2/workspace1".example_table WHERE _tenant = 'tenant2' AND _workspace = 'workspace1' UNION ALL -- 后续其他工作区的SELECT语句
注:每个SELECT语句中添加了“冗余”的分区谓词,目的是提示PostgreSQL在查询视图时跳过无关分区表。EXPLAIN ANALYZE显示这些无关表的查询确实“(never executed)”,但这一点似乎没被查询计划器在规划阶段利用。
性能问题表现
查询由BI工具发起,工具会根据登录用户属性自动为_tenant和_workspace列添加过滤谓词。当工作区数量达到50+后,查询视图的执行计划远不如直接查询底层表高效:
查询视图的慢查询(耗时约1分钟,使用嵌套循环连接)
SELECT * FROM ( SELECT column1, column2, column3 FROM example_view1 WHERE _tenant = 'tenant1' AND _workspace = 'workspace1' ) v1 JOIN ( SELECT column4, column5, column6 FROM example_view2 WHERE _tenant = 'tenant1' AND _workspace = 'workspace1' ) v2 ON v1.column1 = v2.column4
直接查询底层表的快查询(耗时不到1秒,使用哈希连接)
SELECT * FROM ( SELECT column1, column2, column3 FROM "reports/tenant1/workspace1".example_table1 WHERE _tenant = 'tenant1' AND _workspace = 'workspace1' ) v1 JOIN ( SELECT column4, column5, column6 FROM "reports/tenant1/workspace1".example_table2 WHERE _tenant = 'tenant1' AND _workspace = 'workspace1' ) v2 ON v1.column1 = v2.column4
注:子查询是BI工具查询生成器的默认生成方式,无实际业务意义。
核心疑问
如何让查询计划器在规划阶段就知晓:除了匹配_tenant和_workspace谓词的分区表外,其他所有表都不会返回结果,可以直接忽略?目前只有执行阶段才会跳过无关表,但规划阶段仍会考虑所有表,导致执行计划低效。
内容的提问来源于stack exchange,提问作者eskrm
相关产品推荐
相关产品推荐

