MySQL是否在创建新索引时使用现有索引?

时间:2010-10-02 09:52:41

标签: sql mysql indexing query-optimization

我有一张包含数百万条记录的大表。

Table `price`
------------
id 
product 
site 
value

该表是全新的,并且没有创建索引。

然后,我使用以下查询发出了创建新索引的请求:

CREATE INDEX ix_price_site_product_value_id ON price (site, product, value, id);

这花了很长时间,上次我检查时跑了5000多秒,因为机器。

我想知道如果我发布另一个索引创建,它会在进程计算中使用现有索引吗?如果是这样的话?

接下来运行查询1:

CREATE INDEX ix_price_product_value_id ON price (product, value, id);

接下来运行查询2:

CREATE INDEX ix_price_value_id ON price (value, id);

2 个答案:

答案 0 :(得分:5)

  

我想知道如果我发布另一个索引创建,它会在进程计算中使用现有索引吗?如果是这样的话?

不,它不会。

理论上,(site, product, value, id)上的索引具有在这些字段的任何子集上构建索引所需的一切(包括(product, value, id)(value, id)上的索引。)

但是,不支持从辅助索引构建索引。

首先,MySQL不支持快速完整索引扫描(即以物理顺序而不是逻辑顺序扫描索引),从而使索引访问路径比表读取更昂贵。这不是InnoDB的问题,因为表本身始终是聚集的。

其次,这些索引中的记录顺序完全不同,因此无论如何都需要对记录进行排序。

但是,MySQL中索引创建速度的主要问题是它在站点上生成订单(只是将记录逐个插入B-Tree)而不是使用预先排序的源。正如@Daniel所提到的,快速索引创建解决了这个问题。它作为5.1的插件提供,并预装在5.5

答案 1 :(得分:4)

如果您使用的是MySQL 5.1版和InnoDB存储引擎,则可能需要使用InnoDB Plugin 1.0,它支持名为Fast Index Creation的新功能。这允许存储引擎创建索引而不复制整个表的内容。

InnoDB插件概述:

  

从版本5.1开始,MySQL AB推出了“可插拔”存储引擎架构的概念,该架构允许将多个存储引擎添加到MySQL。但是,目前大多数用户只访问了由MySQL AB分发的存储引擎,并链接到二进制(可执行)版本。

     

自2001年以来,MySQL AB已经发布了InnoDB事务存储引擎及其版本(源代码和二进制代码)。从MySQL 5.1版开始,用户可以交换一个版本的InnoDB并使用另一个版本。

     

来源:Introduction to the InnoDB Plugin

快速索引创建概述:

  

在高达5.0的MySQL版本中,如果表有很多行,在具有现有数据的表上添加或删除索引可能会非常慢。 CREATE INDEXDROP INDEX命令通过创建使用请求的索引集定义的新空表来工作。然后,它将现有行逐个复制到新表,随时更新索引。以这种方式将条目插入到索引中,其中键值未被排序,需要随机访问索引节点,并且远非最佳。复制原始表中的所有行后,将删除旧表,并使用原始表的名称重命名该副本。

     

从版本5.1开始,MySQL允许存储引擎创建或删除索引,而无需复制整个表的内容。但是,MySQL版本5.1中的标准内置InnoDB没有利用此功能。但是,使用InnoDB插件,用户在大多数情况下可以比以前的版本更有效地添加和删除索引。

     

...

     

更改聚簇索引需要复制数据,即使使用InnoDB插件也是如此。但是,使用InnoDB插件添加或删除辅助索引要快得多,因为它不涉及复制数据。

     

来源:Overview of Fast Index Creation