我仍然试图了解在MySQL中使用INDEXES的最佳方法。你怎么知道何时将它们合并在一起以及何时将它们分开?
以下是Wordpress帖子表中的索引。看看post_name,post_parent和post_author是如何分开的?然后他们有type_status_date,这是4个字段的混合?
http://img215.imageshack.us/img215/5976/screenshot20120426at431.png
我不明白这背后的逻辑?谁能开导我?
答案 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_type
,post_status
和 post_date
进行过滤和/或排序。对于他们所代表的内容进行有根据的猜测,这可能是WordPress的帖子列表页面的核心查询。所以这三个字段都放在同一个索引中。