0

我仍在努力寻找在 MySQL 中使用 INDEXES 的最佳方法。您如何知道何时将它们合并在一起以及何时将它们分开?

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

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

我不明白这背后的逻辑?任何人都可以启发我吗?

4

2 回答 2

3

这将是一个有点长的答案,但我们开始了。请注意,我不打算在这里处理数据库引擎的差异(MyISAM 和 InnoDB 有不同的方式来实现我试图描述的内容)

关于索引,您必须了解的第一件事是它是存储在磁盘上的单独数据结构。通常这是一个 b-tree 数据结构,包含您已索引的列,还包含指向表中行的指针(此指针通常是主键)。

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

假设您有以下表定义。

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-tree 进行有效的二叉查找操作。

此外,在执行搜索后检索数据时,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 获取数据的角度来看待它。

希望它现在像泥巴一样清澈!

于 2012-04-26T07:37:49.560 回答
1

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

WordPress 可能有一个通用查询,用于过滤和/或排序post_type,post_status post_date. 对它们代表什么进行有根据的猜测,这可能是 WordPress 的帖子列表页面的核心查询。所以这三个字段被放入同一个索引中。

于 2012-04-26T06:36:55.487 回答