oracle 中的散列分区 SQL
Hash partitioning in oracle SQL
我有一个像这样的table:
CREATE TABLE "TS1"
(
"ID" VARCHAR2(32 BYTE) NOT NULL,
"CID" VARCHAR2(70 BYTE) NOT NULL,
"PID" VARCHAR2(21 BYTE) NOT NULL,
"LASTUSAGE" TIMESTAMP (6) NOT NULL,
"CREATIONTIME" TIMESTAMP (6) NOT NULL,
"COSTCENTER" NUMBER NOT NULL
);
ALTER TABLE "TS1" ADD CONSTRAINT "TS1_PRIMARY" PRIMARY KEY ("ID", "CID", "PID");
我试图找到一种划分 table 的好方法,考虑到:
- 我没有在 where 子句中使用 creationTime 的查询(因此范围分区可能不是该字段的最佳解决方案)
- LastUsage 经常更新(因此范围分区可能不是该字段的最佳解决方案)
- 大部分查询在where子句中使用ID、CID、PID
因此,在 ID、CID、PID 上进行 HASH PARTITION 是一个不错的选择。
CREATE TABLE "TS1"
(
"ID" VARCHAR2(32 BYTE) NOT NULL,
"CID" VARCHAR2(70 BYTE) NOT NULL,
"PID" VARCHAR2(21 BYTE) NOT NULL,
"LASTUSAGE" TIMESTAMP (6) NOT NULL,
"CREATIONTIME" TIMESTAMP (6) NOT NULL,
"COSTCENTER" NUMBER NOT NULL
)
PARTITION BY HASH ("ID", CID, PID)
PARTITIONS N; --N = number of partitions
ALTER TABLE "TS1" ADD CONSTRAINT "TS1_PRIMARY" PRIMARY KEY ("ID", "CID", "PID");
如果我使用主键作为参数通过散列进行分区,会不会有问题?
假设在 table TS1 中有很多记录(数百万)我会从这个分区中获得一些性能优势吗?
我原来的错误答案:
按主键分区没有意义,因为每个分区都只有一行。存在与分区相关的开销,因此您希望将分区数保持在合理的数量,例如 1000 以下。
我想我正在考虑将您的主键值作为列表值的列表分区。请参阅下面的评论。
"Most of the queries uses ID, CID, PID in where clause"
这意味着大多数查询都是在主键上进行单行查找,因此分区消除无法使事情变得更快。它可能做的就是使那些不使用键的少数查询 变慢 (因为说使用索引范围扫描的读取可能不那么有效)。
实施分区有三个原因。他们是:
- 数据管理。我们可以使用分区交换将数据加载到单个分区中,或者使用删除或截断分区来处理数据,而不影响 table.
的其余部分
- 可用性。我们可以为每个分区提供一个单独的 table 空间,从而将数据文件损坏或类似情况的影响本地化。
- 性能。使用分区键粒度的查询可能会受益于分区修剪。可能受益的查询是那些将执行范围扫描的查询;如果我们每天将一百万行加载到 table 中,并且我们通常希望检索给定日期的记录,我们将从按天分区中获得很多好处。
- 并发 DML。如果我们的应用程序有大量用户插入、更改和删除记录,我们可能有例如等待 ITL 插槽或闩锁争用,有时已知。 hot blocks。散列分区在这里可以提供帮助,它通过在整个 table.
中分布插入以及所有其他 activity
如果使用情况与您描述的一样,按 ("ID", CID, PID)
的散列进行分区不会帮助您提高性能。它也不会给您带来任何数据管理优势。您似乎不太可能对可用性优势感兴趣(因为数百万行似乎太少而无需担心)。
这样就剩下了并发 DML。如果您要解决的性能问题是写入而不是读取,并且并发 activity 的模式与主键的某些方面对齐(比如大多数 DML 是针对最新的行),那么散列分区可能会减轻闩锁争论。
如果这听起来像您的情况,您应该在具有类似于生产的数据量和 activity 的生产级别的环境中测试分区。 (并不总是那么容易做到。)
否则分区似乎是寻找问题的解决方案。
如何在同一列的 ID、CID、PID 和散列分区上创建本地索引。索引扫描没有好处而不是扫描索引以获得完整 table 它必须扫描单个分区
我有一个像这样的table:
CREATE TABLE "TS1"
(
"ID" VARCHAR2(32 BYTE) NOT NULL,
"CID" VARCHAR2(70 BYTE) NOT NULL,
"PID" VARCHAR2(21 BYTE) NOT NULL,
"LASTUSAGE" TIMESTAMP (6) NOT NULL,
"CREATIONTIME" TIMESTAMP (6) NOT NULL,
"COSTCENTER" NUMBER NOT NULL
);
ALTER TABLE "TS1" ADD CONSTRAINT "TS1_PRIMARY" PRIMARY KEY ("ID", "CID", "PID");
我试图找到一种划分 table 的好方法,考虑到:
- 我没有在 where 子句中使用 creationTime 的查询(因此范围分区可能不是该字段的最佳解决方案)
- LastUsage 经常更新(因此范围分区可能不是该字段的最佳解决方案)
- 大部分查询在where子句中使用ID、CID、PID
因此,在 ID、CID、PID 上进行 HASH PARTITION 是一个不错的选择。
CREATE TABLE "TS1"
(
"ID" VARCHAR2(32 BYTE) NOT NULL,
"CID" VARCHAR2(70 BYTE) NOT NULL,
"PID" VARCHAR2(21 BYTE) NOT NULL,
"LASTUSAGE" TIMESTAMP (6) NOT NULL,
"CREATIONTIME" TIMESTAMP (6) NOT NULL,
"COSTCENTER" NUMBER NOT NULL
)
PARTITION BY HASH ("ID", CID, PID)
PARTITIONS N; --N = number of partitions
ALTER TABLE "TS1" ADD CONSTRAINT "TS1_PRIMARY" PRIMARY KEY ("ID", "CID", "PID");
如果我使用主键作为参数通过散列进行分区,会不会有问题? 假设在 table TS1 中有很多记录(数百万)我会从这个分区中获得一些性能优势吗?
我原来的错误答案:
按主键分区没有意义,因为每个分区都只有一行。存在与分区相关的开销,因此您希望将分区数保持在合理的数量,例如 1000 以下。
我想我正在考虑将您的主键值作为列表值的列表分区。请参阅下面的评论。
"Most of the queries uses ID, CID, PID in where clause"
这意味着大多数查询都是在主键上进行单行查找,因此分区消除无法使事情变得更快。它可能做的就是使那些不使用键的少数查询 变慢 (因为说使用索引范围扫描的读取可能不那么有效)。
实施分区有三个原因。他们是:
- 数据管理。我们可以使用分区交换将数据加载到单个分区中,或者使用删除或截断分区来处理数据,而不影响 table. 的其余部分
- 可用性。我们可以为每个分区提供一个单独的 table 空间,从而将数据文件损坏或类似情况的影响本地化。
- 性能。使用分区键粒度的查询可能会受益于分区修剪。可能受益的查询是那些将执行范围扫描的查询;如果我们每天将一百万行加载到 table 中,并且我们通常希望检索给定日期的记录,我们将从按天分区中获得很多好处。
- 并发 DML。如果我们的应用程序有大量用户插入、更改和删除记录,我们可能有例如等待 ITL 插槽或闩锁争用,有时已知。 hot blocks。散列分区在这里可以提供帮助,它通过在整个 table. 中分布插入以及所有其他 activity
如果使用情况与您描述的一样,按 ("ID", CID, PID)
的散列进行分区不会帮助您提高性能。它也不会给您带来任何数据管理优势。您似乎不太可能对可用性优势感兴趣(因为数百万行似乎太少而无需担心)。
这样就剩下了并发 DML。如果您要解决的性能问题是写入而不是读取,并且并发 activity 的模式与主键的某些方面对齐(比如大多数 DML 是针对最新的行),那么散列分区可能会减轻闩锁争论。 如果这听起来像您的情况,您应该在具有类似于生产的数据量和 activity 的生产级别的环境中测试分区。 (并不总是那么容易做到。)
否则分区似乎是寻找问题的解决方案。
如何在同一列的 ID、CID、PID 和散列分区上创建本地索引。索引扫描没有好处而不是扫描索引以获得完整 table 它必须扫描单个分区