在 Oracle 中按单个值对表进行分区是否值得?

Ива*_*ный 7 oracle partitioning

通常,如果您有一个经常查询表的列,则应该在其上粘贴索引。但是,如果事先知道所有可能的值,是否也值得按此列对表进行分区?假设您有一个表,AUDIT其中的TenantId列只能包含值:1, 2所有 SELECT语句都有一个WHERETenantId参数的子句。

那么,通过 TenantId 对该表进行分区是否有益?如果是这样,您还会在TenantId列上创建索引吗?

partition by list (TENANTID)
(
  partition TENANT1 values (1),
  partition TENANT2 values (2)
)
Run Code Online (Sandbox Code Playgroud)

我做了一个小实验:插入 1M 随机生成的 TenantId 记录,从而创建:

  • 499652 条记录,TenantId=1
  • 500348 条记录,TenantId=2

以下是语句的查询计划:

SELECT * FROM table1 WHERE TENANTID=2
Run Code Online (Sandbox Code Playgroud)

普通表(无索引,无分区) 普通表查询计划 位图索引: 位图索引查询计划 分区: 分区查询计划

顺便说一句,如果我同时拥有索引和分区,查询计划使用分区而不是索引,因此该计划看起来与上面显示的第二个完全相同。

显然分区获胜,但是呢? 显然,执行计划中的成本列并不是判断 SQL 语句响应时间的真实成本的可靠方法

那么,什么是最好的方法呢?如何选择一个?

Flo*_*ita 5

我的观点是,以所呈现的方式对该表进行分区可能是有用的。

如果进行完整扫描,您的查询将快两倍(在分区几乎相等的情况下)。

如果您的查询具有另一种过滤器/条件并使用索引,则分区没有用,因为索引的级别几乎不受值数量加倍的影响。

更新:对于您所做的测试(SELECT * FROM table1 WHERE TENANTID=2),可以肯定分区是最好的。位图解决方案需要扫描索引,然后扫描包含行的所有表块tenantid=2(它知道行是什么)。但是分区会导致只扫描tenantid=2的表分区。它们在物理上是分开的tenantid=1

因此,两次扫描(索引扫描+表扫描)与一次表扫描(可能更小)。