Oracle数据库支持多种类型的索引,每种类型的索引都适合于不同的应用场景。一下是一些常见的索引类型以及他们的应用场景:
1、B-Tree索引(B树索引):这是Oracle最常用的索引类型。B-Tree索引将数据值映射到行ID,可以用于等于、不等于、范围查询等操作。
如果你的查询通常包含等于或范围查询条件,那么B-Tree索引可能是一个好的选择。
oracle会自动为表的主键列建立索引,这个默认的索引是普通的B-tree索引。索引默认按照升序存储列值。普通索引适合检索区分度高的数据列。
例如,如果你经常需要根据员工的姓名查询员工信息,那么你可以在employees表的last_name列上创建一个B-Tree索引:
CREATE INDEX idx_employees_last_name ON employees(last_name);
2、Bitmap索引(位图索引):Bitmap索引用于处理低基数数据,也就是列值有很少的不同值(适合低区分度的列,即列的唯一值除以行数为一个很小的值,接近0)例如性别、婚姻状况等。Bitmap索引在数据仓库环境中很有用,但是在OLTP环境中,由于并发插入、更新、删除操作可能导致锁冲突,一般不建议使用。
例如,如果你经常需要根据员工的性别查询员工信息,那么你可以在“employees”表的 "gender"列上创建一个Bitmap索引。
CREATE BITMAP INDEX idx_employees_gender ON employees(gender);
3、function-Based索引(FUNCTION-BASED NORMAL,降序索引/函数索引):这种类型的索引允许你在函数或表达式上创建索引,这对于处理复杂查询非常有用。如果你的查询经常包含函数或表达式,那么function-Based索引可能是一个好的选择。
是B-tree的一个衍生物,它的变化就是列在索引中的存储方式从升序变成了降序。在oracle索引视图中查看到索引类型是function-based normal.
例如,如果你经常需要根据员工的入职年份查询员工信息,那么你可以创建一个Function-Based索引:
CREATE INDEX idx_employees_hire_year ON employees(EXTRACT(YEAR FROM hire_date));
CREATE INDEX idx_emp1_sal ON emp(sal DESC) TABLESPACE indexdata;
4、Partitioned索引(分区索引):这种类型的索引用于处理分区表,如果你的表是分区的,那么你可以创建一个partition索引。
partitioned索引可以是本地的(本地索引:local index,每个分区有自己的索引)或者全局的(全局索引:global index,所有分区共享一个索引)。
全局索引包括全局分区索引(global partitioned index)、全局非分区索引(global non-partitioned index,即普通索引)。 全局索引只有一类,即全局前缀索引(prefixed global index),索引分区键必须作为索引定义的第一列。 一般情况下,大多数分区操作(如删除一个旧分区)都会使全局索引无效,除非重建全局索引,否则无法使用。 本地索引可以有两类,即Local prefixed index(局部前缀索引)、Local nonprefixed index(局部非前缀索引)。 局部前缀索引:以分区键作为索引定义的第一列。 局部非前缀索引:分区键没有作为索引定义的第一列。 局部分区索引随表对索引完成相应的分区(即索引会使用与底层表相同的机制分区),每个表分区都有一个索引分区,并且只索引该表分区。
局部索引的唯一性,Oracle只保证索引分区内部的唯一性,跨分区的唯一性无法保证。
常见的索引相关问题和可能的解决方案:
1、查询不使用索引
如果你发现查询没有使用预期的索引,可能是因为Oracle查询优化器认为全表扫描比使用索引更有效,或者查询的谓词阻止了索引的使用。
解决方案:你可以使用Oracle的EXPLAIN PLAN工具来查看查询的执行计划,确认索引是否被使用,如果未被使用,确定原因。你可以尝试重新编写查询,使其更适合使用索引,或者考虑增加或调整索引以改进性能。
例如,以下的查询可能无法使用索引:
SELECT * FROM employees WHERE TO_CHAR(hire_date, ‘YYYY’) = ‘2023’;
你可以将其改写为:
SELECT * FROM employees WHERE hire_date BETWEEN TO_DATE(‘2023-01-01’, ‘YYYY-MM-DD’) AND TO_DATE(‘2023-12-31’, ‘YYYY-MM-DD’);
2、索引碎片
如果你的表经常进行插入、删除操作,索引可能会变得碎片化,这会影响查询性能。
解决方案:你可以定期重建索引以减少碎片。但是,需要注意的是,重建索引可能需要大量的系统资源,并且在重建索引期间,索引可能无法 使用。
以下是重建索引的SQL命令:
ALTER INDEX idx_employees_last_name REBUILD;
3、过多的索引
如果一个表有过多的索引,这可能会影响插入和更新操作的性能,因为每次插入或更新都需要更新所有的索引。
解决方案:你应该定期审查索引,并删除不再需要的索引。当创建新的索引时,你也应该考虑索引的成本和溢出。
以下是删除索引的SQL命令:
DROP INDEX idx_employees_last_name;
索引失效的原因和对策:
在Oracle数据库中,即使你为表创建了索引,有时查询优化器可能也不会使用这些索引,这被称为索引失效。以下是一些可能导致索引失效的常见原因和对策:
1、数据分布不均
如果索引列的值分布不均,例如某个值占据了大部分行,那么Oracle可能会选择进行全表扫描,而不是使用索引。
对策:你可以考虑重新设计表结构或调整查询,以避免在分布不均的列上进行查询。你也可以考虑使用位图索引,它在处理分布不均的数据时效果更好。
2、在索引列上使用 函数或表达式
如果查询在索引列上使用了函数或表达式,Oracle可能无法使用索引。
对策:你可以尝试重新编写查询,避免在索引列上使用函数或表达式。如果无法避免,你可以考虑创建函数索引。
例如,以下的查询可能无法使用索引:
SELECT * FROM employees WHERE TO_CHAR(hire_date, ‘YYYY’) = ‘2023’;
你可以将其改写为:
SELECT * FROM employees WHERE hire_date BETWEEN TO_DATE(‘2023-01-01’, ‘YYYY-MM-DD’) AND TO_DATE(‘2023-12-31’, ‘YYYY-MM-DD’);
3、索引统计信息过时
Oracle的查询优化器依赖于索引的统计信息来选择执行计划。如果统计信息过时或不准确,Oracle可能无法正确选择索引。
对策:你应该定期收集索引和表的统计信息。你可以使用Oracle的DBMS_STATS包来收集统计信息。
EXEC DBMS_STATS.GATHER_TABLE_STATS(user, ‘employees’);
什么情况下需要常见索引,什么情况下不需要创建索引,以及索引最大能创建几个比较合理,索引的工作原理和过程是怎样的?
在决定何时创建索引时,需要考虑许多因素,包括查询的性质、数据的性质、以及表的大小和变化率。
何时需要创建索引:
1、频繁查询的列:如果一个列被频繁地用在查询条件(如WHERE子句)中,那么在这个列上创建索引可能有助于提高查询性能。
2、主键和外键列:主键和外键列通常是索引的好候选者,因为它们经常用于连接和查找操作。
3、具有唯一值的列:如果一个列的值是唯一的或几乎唯一的,那么在这个列上创建索引可以提高查询性能。
何时不需要创建索引:
1、不常查询的列:如果一个列很少或者从不用于查询条件,那么在这个列上创建索引可能是浪费的。
2、具有高度重复值的列:如果一个列的值有很高的重复率,那么在这个列上创建索引可能不会提高查询性能,反而会浪费存储空间和处理时间。
3、频繁更新和 插入的表:如果一个表经常进行更新或插入操作,那么过多的索引可能会降低这些操作的性能,因为每次数据变化都需要更新索引。
对于表新增、更新或删除一条数据,索引是怎么变化的?
当表中的数据发生变化时,任何关联的索引都需要更新以反映这些变化。这是因为索引本质上是一个指向表中特定行的指针集合,当这些行的数据改变时,索引需要调整以保持正确的引用。
以下是对于插入、更新和删除操作,索引如何变化的具体例子:
插入:当向表中插入一行数据时,需要在关联的所有索引中添加相应的条目。例如,如果我们有一个员工表并且在last_name列上有一个索引,当我们添加一个新员工时,需要在last_name索引中添加一个新条目,这个条目将新员工的姓与他的行位置关联起来。
更新:当更新表中的一行数据时,如果更新的列是被索引的,那么相应的索引条目也需要更新。例如,如果我们更新上述员工表中一个员工的姓(last_name),那么我们需要在last_name索引中找到这个员工的条目并更新它,以反映姓的新值。
删除:当从表中删除一行数据时,需要从关联的所有索引中删除相应的条目。例如,如果我们从上述员工表中删除一个员工,那么我们需要在last_name索引中找到这个员工的条目并删除它。
需要注意的是,由于索引需要随着表数据的变化而更新,所以在数据频繁变动的表上维护索引可能会有一定的开销。在决定是否在一个表上创建索引时,需要权衡索引带来的查询性能提升和更新开销之间的平衡。
空值的列适合建什么索引?
在空值较多的列上创建索引,需要根据具体的查询需求和数据特性来决定。以下是一些可能的情况和对应的建议:
位图索引
如果一个列中的空值很多,且该列的非空值是低基数的(即只有少数几个不同的值),那么位图索引可能是一个好的选择。位图索引适用于低基数数据,而且可以有效地处理空值。在位图索引中,每个可能的值(包括NULL)都有一个对应的位图,所以可以有效地查询和操作空值。
函数索引
如果你需要在空值列上进行特定的查询(例如,查找所有空值或非空值的行),你可以考虑使用函数索引。例如,你可以在 NVL(column, ‘N/A’) 或者 COALESCE(column, ‘N/A’) 上创建函数索引,这样即使原列中有很多空值,也能有效地查询和操作这些值。
B-Tree索引
如果一个列中有很多空值,但你并不需要针对这些空值进行查询,你可能仍然想要在这个列上创建一个B-Tree索引。B-Tree索引不会包含空值,所以如果你的查询主要针对非空值,B-Tree索引仍然可以提供好的性能。
总的来说,选择何种类型的索引主要取决于你的查询需求和数据特性。你应该基于你的应用的实际需求来选择最合适的索引类型,并通过测试和性能监控来验证你的选择。