我正在使用Oracle 12c。
考虑一个表名GRID_CELLS,它存储 100,000 x 100,000 网格单元格数据。列如下:
- X 数
- Y 数
- CELL_VALUE编号
索引由 (X, Y( 组成,它是主键。
由于它是网格单元格数据,因此几乎所有的"单元格"都有记录。
如果查询如下所示:
select * from GRID_CELLS where X >= 100 and X <= 200 and Y >= 100 and Y <= 200
Oracle 将选择索引范围扫描,并执行以下操作:
- 从根节点遍历 B 树索引以查找第一个叶节点
- 通过最后一个叶节点按 rowid 访问表行一直扫描叶节点
也就是说,Oracle 读取大约 100,000 * 100 条记录的叶节点,这将比以下(假设(操作慢得多。
- 从根遍历 B 树索引以查找 (>=100,>=100( 的第一个叶节点
- 扫描叶节点,直到找到 Y 值大于 200 的记录
- 停止叶节点扫描,并从根节点重新遍历下一个 X 的 B 树索引
- 重复 2 和 3
甲骨文能这样吗?如果是这样,怎么能强迫它这样做呢?还是有其他最佳解决方案?
顺便说一句,我们不能使用分区。因此,分区不是解决方案。
更新
我已经根据下面的评论测试了 2 位图索引配置。结果是积极的。它比B树索引范围扫描快5~10倍。
但是,如果 Oracle 在范围扫描 B 树索引时跳过叶节点,那仍然会很好。
位图索引是一种方法。使用位图索引时,即使是星形转换也是最佳的。位图索引的问题在于,当 X 和 Y 具有许多不同的值时,它们很大且查询速度较慢。与行数相比,表中存在的不同 X 和 Y 值总数较少时,它们最适合。
还有一些额外的步骤可以加快查询速度:
您可以按 X 和/或 Y 对表进行分区。在这种情况下,速度增益取决于 X 和 Y 值的分布,以及查询是否选择了值范围。
您可以在 X 和 Y 上创建函数索引,或者将 X 和 Y 连接成一个字符串,然后在该字符串上创建索引。然后,您将只有一个密钥。这可能是最好的解决方案,因为它将执行复杂性降低了一个程度。
如果执行期间的磁盘 I/O 很高,将此表转换为 IOT(索引组织的表(将为您带来好处,但对于具有许多列的表,通常就是这种情况。
在
决定索引策略时,您必须始终牢记此表在生产环境中的读/写比率。如果有高读取计数(SELECT(和低写入计数(INSERT(,那么您需要将大部分处理放在写入部分:对表进行分区,创建功能索引等。如果写入计数高,读取计数低,并且 SELECT 速度不是那么重要,那么 X 和 Y 上的一个索引是最佳解决方案。