MySQL索引以及何时对它们进行分组

时间:2012-04-26 06:34:30

标签: mysql

我仍然试图了解在MySQL中使用INDEXES的最佳方法。你怎么知道何时将它们合并在一起以及何时将它们分开?

以下是Wordpress帖子表中的索引。看看post_name,post_parent和post_author是如何分开的?然后他们有type_status_date,这是4个字段的混合?

http://img215.imageshack.us/img215/5976/screenshot20120426at431.png

我不明白这背后的逻辑?谁能开导我?

2 个答案:

答案 0 :(得分:3)

这是一个很长的答案,但我们走了。请注意我不会在这里处理数据库引擎的差异(MyISAM和InnoDB有不同的方式来实现我想要描述的内容)

首先要了解一个索引,它是一个存储在磁盘上的独立数据结构。通常,这是一个b树数据结构,其中包含已编入索引的列,并且还包含指向表中行的指针(此指针通常是主键)。

与数据一起存储的唯一索引是主键索引。 因此主键索引就是表格。

让我们假设您有以下表格定义。

CREATE  TABLE `Student` (
 `StudentNumber` INT NOT NULL ,
 `Name` VARCHAR(32) NULL ,
 `Surname` VARCHAR(32) NULL ,
 `StudentEmail` VARCHAR(32) NULL ,
 PRIMARY KEY (`StudentNumber`) );

由于我们在StudentID上有一个主键,因此会有一个索引包含主键和索引中的其他列。如果你不得不查看索引中的数据,你可能会看到类似这样的东西。

1 , John ,Doe ,Jdoe@gmail.com

正如您所看到的,这是表格数据,再次向您显示主键索引是表格。

StudentNumber列已编制索引,允许您有效地搜索其中的其余数据与密钥一起存储。因此,如果运行以下查询:

SELECT * FROM Student WHERE StudentNumber=1

MySQL将使用主索引快速查找行并读取与索引列一起存储的数据。由于有一个索引MySQL可以使用索引在b树上进行有效的二进制搜索操作。

此外,在执行搜索后检索数据时,MySQL可以从索引中读取数据,因此我们在索引中使用1次操作来检索数据。现在,如果我运行以下查询:

SELECT * FROM Student WHERE Name ='Joe' 

MySQL将检查是否有可用于加速查询的索引。但是在我的情况下,名称上没有索引,因此MySQL会从第一行到最后一行一次从表中顺序读取一行。

在每一行,它将根据where子句计算行并返回匹配行。所以基本上它从上到下读取主键索引。请记住,主键索引是表。

如果我运行以下声明:

 ALTER TABLE `TimLog`.`student` 
ADD INDEX `ix_name` (`Name` ASC) ;
 ALTER TABLE `TimLog`.`student` 
ADD INDEX `ix_surname` (`Surname` ASC) ;

MySQL会在Student表上创建新索引。这将远离磁盘上的表存储,内部数据将如下所示:

Data in ix_Name
John, 1 <--PRIMARY KEY VALUE

Data in ix_Surname
Doe, 1  <--PRIMARY KEY VALUE

请注意,ix_Name索引中的数据是名称和主键值。好的,如果我运行前面的select语句,MySQL将读取ix_name索引并获取匹配项的主键值,然后使用主键索引获取其余数据。

因此,从索引获取数据的操作数为2 。在索引中找到匹配的行,然后在主键上进行查找以获取行数据。

您现在有以下查询:

SELECT * FROM Student WHERE Name='John' AND surname ='Doe' 

这里MySQL不能使用这两个索引,因为这会浪费操作。如果MySQL必须在此查询中使用这两个索引,则会发生以下情况(这不应该发生)。

1 Find in the ix_Name the rows with the value John
2 Read the primary key that matches to get the row data
3 Store the matching results
4 Find in the ix Surname the rows with the value Doe
5 Read the primary key that matches to get row data.
6 Store the matching results
7 Take the Name results and Surname results and merge them
8 Return query results.

这实际上是对IO的浪费,因为MySQL会随后读取该表两次。基本上使用一个索引会比尝试使用两个索引更好(我将在一个momnet中解释为什么)。 MySQL将选择1个索引用于这个简单的查询。

那么MySQL如何决定使用哪个索引?

MySQL在内部保留有关索引的统计信息。这些统计数据告诉MySQL基本上索引的唯一性。因此,为了参数,可以说姓氏索引(ix_surname)比名称索引(ix_name)更独特,MySQL会使用姓氏索引(ix_surname)。

因此查询检索将是这样的:

1 Use the ix_surname and find rows that match the value Doe
2 Read the primary key and apply the filter for the value John on the actual column data in the row.
3 Return the matched row.

正如您所看到的,此搜索中的操作数量要少得多。我简化了许多技术细节。索引是一个有趣的事情要掌握,但你必须从如何以最小的IO获取数据的角度来看待它。

希望它现在像泥一样清晰!

答案 1 :(得分:1)

MySQL通常不能一次使用多个索引。这意味着,例如,当您有一个对两个字段进行过滤或排序的查询时,您将它们放在同一个索引中。

WordPress可能有一个常见的查询,可以对post_typepost_status post_date进行过滤和/或排序。对于他们所代表的内容进行有根据的猜测,这可能是WordPress的帖子列表页面的核心查询。所以这三个字段都放在同一个索引中。