几种索引扫描方式

 

1)索引唯一扫描 如果查询时是通过unique或primary key约束来保证只返回一条数据,那么优化器就会选择索引唯一扫描,这是访问一条数据的最快方式。

2)索引范围扫描

索引键非唯一,当遇到如下条件时会使用索引范围扫描:

1.col=:b1

2.col<:b1

3.col>:b1

3)索引降序范围扫描

与2)中的情况相同,只不过2)默认是安装 升序进行查找的,而这里是按降序进行查找,如:

select line_item_id,order_id from order_items where order_id<:b1 order by order_id desc;

4) 跳跃式索引(Skip Scan Index)。当表有一个复合索引,而在查询中有除了索引中第一列的其他列作为条件,并且优化器模式为CBO,这时候查询计划就有可能使用到SS,另外通 过使用提示index_ss(CBO下)来强制使用SS。跳跃式索引使复合索引从逻辑上分为几个小的子索引,分的条件就是复合索引列的第一个字段,可以这 样理解,Oracle 将索引从逻辑上划分为a.num_distinct个子索引,每次对一个子索引进行扫描。因此SS的索引扫描成本为a.num_distinct.而且使用SS的条件需要第一列的distinct num要足够小

5)index full scan和Index Fast Full Scan(全索引扫描和快速全索引扫描)

index full scan和index fast full scan是指同样的东西吗?答案是no。两者虽然从字面上看起来差不多,但是实现的机制完全不同。我们一起来看看两者的区别在哪里?
首先来看一下IFS,FFS能用在哪里:在一句sql 中,如果我们想搜索的列都包含在索引里面的话,那么index full scan 和 index fast full scan 都可以被采用代替full table scan。比如以下语句:
  
  SQL> CREATE TABLE TEST AS SELECT * FROM dba_objects WHERE 0=1;
  
  SQL> CREATE INDEX ind_test_id ON TEST(object_id);
  
  SQL> INSERT INTO TEST
  SELECT  *
  FROM dba_objects
  WHERE object_id IS NOT NULL AND object_id > 10000
  ORDER BY object_id DESC;
  
  17837 rows created.
  
  SQL> analyze table test compute statistics for table for all columns for all indexes;
  
  Table analyzed.
  SQL> set autotrace trace;
  
  SQL> select object_id from test;
  
  17837 rows selected.
  
  Execution Plan
  ----------------------------------------------------------
    0   SELECT STATEMENT ptimizer=CHOOSE (Cost=68 Card=17837 Bytes=71348)
    1  0  TABLE ACCESS (FULL) OF 'TEST' (Cost=68 Card=17837 Bytes=71348)
  
  这时候Oracle 会选择全表扫描,因为 object_id 列默认是可以为null的,来修改成 not null:
  
  
  SQL>alter table test modify(object_id not null);
  
  SQL> select object_id from test;
  
  17837 rows selected.
  
  Execution Plan
  ----------------------------------------------------------
    0   SELECT STATEMENT ptimizer=CHOOSE (Cost=11 Card=17837 Bytes=71348)
    1  0  INDEX (FAST FULL SCAN) OF 'IND_TEST_ID' (NON-UNIQUE) (Cost=11 Card=17837 Bytes=71348)
  
  当然我们也可以使用index full scan:
  
  
  SQL> select/*+ index(test ind_TEST_ID)*/ object_id from test;
  
  17837 rows selected.
  
  Execution Plan
  ----------------------------------------------------------
    0   SELECT STATEMENT ptimizer=CHOOSE (Cost=41 Card=17837 Bytes=71348)
    1  0  INDEX (FULL SCAN) OF 'IND_TEST_ID' (NON-UNIQUE) (Cost=101 Card=17837 Bytes=71348)
  
  我们看到了两者都可以在这种情况下使用,那么他们有什么区别呢?有个地方可以看出两者的区别, 来看一下两者的输出结果,为了让大家看清楚一点,我们只取10行。
  
  INDEX FAST FULL SCAN
  
  SQL> select object_id from test where rownum<11;
  
   OBJECT_ID
  ----------
     66266
     66267
     66268
     66269
     66270
     66271
     66272
     66273
     66274
     66275
  10 rows selected.
  
  
  INDEX FULL SCAN
  
  SQL> select/*+ index(test ind_TEST_ID)*/ object_id from test where rownum<11;
  
   OBJECT_ID
  ----------
     10616
     12177
     12178
     12179
     12301
     13495
     13536
     13539
     13923
     16503
  10 rows selected.
  
  可以看到两者的结果完全不一样,这是为什么呢?这是因为当进行index full scan的时候oracle 定位到索引的root block,然后到branch block(如果有的话),再定位到第一个leaf block, 然后根据leaf block的双向链表顺序读取。它所读取的块都是有顺序的,也是经过排序的。
  
   而index fast full scan则不同,它是从段头开始,读取包含位图块,root block,所有的branch block, leaf block,读取的顺序完全有物理存储位置决定,并采取多块读,没次读取db_file_multiblock_read_count个块。

使用这两种索引扫描需要表的索引字段至少有一个是not null限制。

快速全索引扫描比普通索引扫描速度快是因为快速索引扫描能够多块读取,并且能并行处理。

普通快速索引扫描可以减少排序操作。

6)Index Join索引连接

我们都知道表与表之间可以连接,那么索引与索引之间呢?当然也可以。索引连接是一种索引之间的hash连接,当查找的字段都已经包括在索引中时,就不需要去访问表的内容,直接通过访问多个索引就能得到结果。Index join只能在CBO使用的情况下进行。

<think> 我们正在回答用户关于MySQL索引类型的问题。根据引用内容,我们可以将MySQL索引类型分为按存储结构分类和按功能分类两种维度。 注意:用户之前的问题是关于VARCHAR和TEXT存储机制的区别,但当前新问题是询问索引类型,因此我们需要专注于索引类型的回答。 根据引用[1]和引用[3]提供的信息: 1. 按存储结构分类:聚簇索引和非聚簇索引(也称为二级索引) 2. 按功能分类:普通索引、唯一索引、主键索引、全文索引、组合索引(联合索引)等。 我们需要详细说明这些索引类型,并注意引用标记。 此外,根据引用[2],全文索引是为文本搜索设计的,适用于VARCHAR、CHAR或TEXT类型列。 因此,我们将索引类型整理如下: 一、按存储结构分类 1. 聚簇索引(Clustered Index) - 特点:数据与索引存储在一起,叶子节点就是数据行。InnoDB中主键索引就是聚簇索引。每张表只能有一个聚簇索引。 - 适用场景:主键查询、范围查询(因为数据物理顺序存储)[^1]。 2. 非聚簇索引(Secondary Index / Non-Clustered Index) - 特点:叶子节点存储的是主键值(InnoDB)或数据的物理地址(MyISAM)。查询时需要回表(通过主键值再去聚簇索引中查找行数据)。一个表可以有多个非聚簇索引。 - 适用场景:非主键列的查询[^1]。 二、按功能分类 1. 普通索引(Index) - 最基本的索引,没有任何约束,仅用于加速查询。 2. 唯一索引(Unique Index) - 索引列的值必须唯一,允许有空值。 - 适用场景:防止出现重复的值,如身份证号、邮箱等[^3]。 3. 主键索引(Primary Key Index) - 特殊的唯一索引,不允许有空值。在InnoDB中,主键索引就是聚簇索引。 4. 全文索引(Fulltext Index) - 专门用于全文搜索,仅适用于MyISAM和InnoDB(MySQL5.6+)引擎,且只能用于CHAR、VARCHAR和TEXT列[^2]。 - 适用场景:大文本字段的搜索,如文章内容、评论等。 5. 组合索引(Composite Index / 联合索引) - 在多个列上建立的索引索引的顺序很重要,因为MySQL使用最左前缀原则。 - 适用场景:多条件查询,例如WHERE条件中同时使用多个列[^3]。 - 注意:组合索引比多个单列索引更高效(引用[3]提到,多个单列索引效率低于组合索引)。 此外,还有空间索引(用于地理空间数据类型),但用户没有提到,引用中也没有,可以省略。 最后,按照要求生成相关问题。 注意:所有引用标记要自然地添加在引用内容的末尾。 </think> ### MySQL索引类型详解 #### 一、按存储结构分类 1. **聚簇索引(Clustered Index)** - **特点**: - 数据与索引存储融合(叶子节点即数据本身) - 每表仅有一个(默认主键索引) - 物理存储按主键值有序排列 - **适用场景**: - 主键范围查询(如`WHERE id BETWEEN 100 AND 200`) - 需要高效主键检索的场景 - **InnoDB实现**: ```sql CREATE TABLE users ( id INT PRIMARY KEY, -- 自动生成聚簇索引 name VARCHAR(50) ); ``` [^1] 2. **非聚簇索引(二级索引)** - **特点**: - 叶子节点存储主键值(非数据本身) - 查询需回表操作(二次查找) - 单表可建多个 - **数据结构示例**: ``` B+树叶子节点: [索引键值 -> 主键值] ↓ 回表查找 ↓ [实际数据行] ``` - **适用场景**: - 非主键字段查询(如`WHERE email='user@example.com'`) - 覆盖索引优化(避免回表)[^1] #### 二、按功能分类 1. **普通索引(INDEX)** - 基础索引类型,无唯一性约束 - 创建语法: ```sql CREATE INDEX idx_name ON users(name); ``` 2. **唯一索引(UNIQUE)** - 强制字段值唯一性(允许NULL值) - 创建语法: ```sql CREATE UNIQUE INDEX idx_email ON users(email); ``` 3. **主键索引(PRIMARY KEY)** - 特殊的唯一索引 + 聚簇索引 - 不允许NULL值 - 隐式创建: ```sql CREATE TABLE orders ( order_id INT AUTO_INCREMENT PRIMARY KEY -- 自动创建主键索引 ); ``` 4. **全文索引(FULLTEXT)** - **特点**: - 专为文本搜索设计(支持`VARCHAR`/`CHAR`/`TEXT`) - 使用倒排索引结构 - 支持自然语言搜索 - **创建示例**: ```sql ALTER TABLE articles ADD FULLTEXT idx_content(content); ``` - **搜索语法**: ```sql SELECT * FROM articles WHERE MATCH(content) AGAINST('database optimization'); ``` [^2] 5. **组合索引(联合索引)** - **特点**: - 多列组合的单一索引(列顺序敏感) - 遵循最左前缀原则 - **创建示例**: ```sql CREATE INDEX idx_city_age ON users(city, age); ``` - **生效场景**: ```sql -- ✅ 生效:使用索引左前缀 SELECT * FROM users WHERE city='Beijing' AND age>25; -- ❌ 失效:跳过左前缀 SELECT * FROM users WHERE age>30; ``` - **性能优势**: - 比多个单列索引更高效(减少索引合并操作) - 支持索引覆盖扫描[^3] --- ### 索引类型对比矩阵 | **索引类型** | **唯一性** | **NULL值** | **存储关联** | **适用场景** | |--------------|------------|------------|--------------------|----------------------------| | 主键索引 | ✅ | ❌ | 聚簇索引 | 主键查询 | | 唯一索引 | ✅ | ✅ | 非聚簇索引 | 业务唯一值(邮箱/手机号) | | 普通索引 | ❌ | ✅ | 非聚簇索引 | 高频查询字段 | | 全文索引 | ❌ | ✅ | 独立倒排索引 | 大文本搜索 | | 组合索引 | ❌ | ✅ | 非聚簇索引 | 多条件联合查询 | --- ### 相关问题延伸 1. **为什么组合索引需要遵循最左前缀原则?其底层实现逻辑是什么?** 2. **全文索引与`LIKE '%keyword%'`查询在性能和结果准确性上有何本质区别?** 3. **如何优化使用非聚簇索引时的回表查询性能?** 4. **在何种场景下应该优先选择哈希索引而非B+树索引?** 5. **MySQL 8.0的倒排索引优化对全文搜索性能带来哪些提升?** [^1]: 聚簇索引与非聚簇索引的存储特性对比 [^2]: 全文索引的文本搜索适用场景 [^3]: 组合索引相比单列索引的效率优势
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值