我试图准确理解多字段索引中的确切内容和用途。我已阅读this existing question(以及更多)以及其他网站/资源(MySQL性能博客,Percona slidehares等),但我并不完全相信我在该主题上发现的内容是最新且准确的。因此,请在我重复一些我认为我知道的事情时请耐心等待。
通过明智地建立索引,我不仅可以减少匹配查询条件所需的时间,还可以减少在查询结果中获取所需字段所需的时间。
索引只是完整数据的有序重复子集,与指针(MyISAM)或PKs(InnoDB)配对,我可以比全表更有效地搜索。
鉴于上述情况,使用索引来匹配我的条件实际上就像获取我想要的结果一样,除了我创建了这个特殊目的表(索引),它得到了我的中间结果设置得很快;使用这个中间结果集,我可以比执行全表扫描更有效地检索我最终所需的结果集。
此外,如果索引覆盖了我的查询中的所有字段(不仅仅是条件),而不是中间结果集,索引将为我提供所需的一切,而无需从整个表中获取任何行
InnoDB表聚集在PK上,因此具有连续PK的行可能存储在同一个块中(每个块给定多行),并且我可以相当有效地获取具有连续PK的行范围。
MyISAM表未集群;有一些隐藏的内部行排序与PK(或任何索引)没有固定的关系,所以每当我想要获取一组行时,我可能必须为每一行检索不同的块 - 即使这些行有连续的PK。
假设上述内容至少一般都是准确的,这就是我的谜题。我有一个缓慢变化的维度表,使用以下列(或多或少)和使用MyISAM定义:
dim_owner_ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
person_ID INT UNSIGNED NOT NULL,
raw_name VARCHAR(92) NOT NULL,
first VARCHAR(30),
middle VARCHAR(50),
last VARCHAR(30),
suffix CHAR(3),
flag CHAR(1)
每个“所有者”都是具有特定名称的特定个人的唯一实例,因此如果Sue Smith将其姓名更改为Sue Brown,则会导致两行除last
字段和代理钥匙。我的理解是,在内部强制执行此约束的唯一方法是:
UNIQUE INDEX uq_owner_complete (person_ID, raw_name, first, middle, last, suffix, flag)
这基本上会复制整个表格(代理键除外)。
我还需要索引其他一些字段以进行快速连接和搜索。虽然会有一些写入,并且磁盘空间既不是自由也不是无限,读取性能绝对是这里的第一优先级。这些较小的索引应该很好地覆盖将对表运行的查询的条件,但几乎在每种情况下,都需要选择整行。
考虑到这一点:
在坚持使用短的单字段索引(可能的前缀)和扩展每个索引以覆盖整个表格之间是否有任何合理的中间立场?
后者与在磁盘上存储整个数据集五次有什么不同,但每次都有不同的排序?
将PK /代理ID添加到每个较小的索引是否有任何好处,希望查询优化器能够处理某种索引合并魔术?
如果这是一个InnoDB索引,那么PK已经存在,但是因为它是MyISAM,所以它有指向完整行的指针。因此,如果我正确理解事物,那么将PK添加到任何其他索引是没有意义的(没有双关语),除非这样做允许直接从索引中检索所需的结果集。这不太可能。
我理解,如果我觉得我很难进行优化,也许我就是这样,但我需要使用这个数据库执行的任务需要花费几周时间,所以每一点都有帮助。
答案 0 :(得分:1)
你必须理解一个概念。索引(InnoDB或MyiSAM,ether Primary或secondary)是一种称为" B + tree"的数据结构。
B +树中的每个节点都是一对(k,v),其中k是键,v是值。如果你在last_name上建立索引,你的密钥将是" Smith"," Johnson"," Kuzminsky"等。
索引中的值是一些数据。如果索引是辅助索引,则数据是主键值。
因此,如果您在last_name上构建索引,则每个节点都是一对(last_name,id),例如: (" Smith",5)。
主索引是一个索引,其中k是主键,数据是所有其他字段。
请记住以上内容让我评论一些观点:
通过明智地建立索引,我不仅可以减少匹配查询条件所需的时间,还可以减少在查询结果中获取所需字段所需的时间。
不完全是。如果您的二级索引是好的,您可以根据查询条件快速找到v。例如。你可以通过姓氏快速找到PK。
索引只是完整数据的有序重复子集,与指针(MyISAM)或PK(InnoDB)配对,我可以比完整表更有效地搜索。
索引是B +树,其中每个节点都是一对索引字段值和PK。
鉴于上述情况,使用索引来匹配我的条件实际上就像获取我想要的结果一样,除了我创建了这个专用表(索引),它让我很快得到了一个中间结果集;使用这个中间结果集,我可以比执行全表扫描更有效地检索我最终所需的结果集。
不完全是。如果没有索引,则您必须扫描整个表并仅选择last_name =" Smith"的记录。但你有索引(last_name,PK),所以有关键" Smith"你可以快速找到所有PK,其中last_name =" Smith"。然后你可以快速找到你的完整结果(因为你不仅需要姓氏,还需要名字)。所以你是对的,查询如SELECT * FROM table WHERE last_name =" Smith"分两步执行:
此外,如果索引覆盖了我的查询中的所有字段(不仅仅是条件),而不是中间结果集,索引将为我提供所需的一切,而无需从整个表中获取任何行。
完全。如果您的索引实际上是(last_name,first_name,id)并且您的查询是SELECT first_name WHERE last_name =" Smith"你不做第二步。您在辅助索引中有第一个名称,因此您不必转到主索引。
InnoDB表聚集在PK上,因此具有连续PK的行可能存储在同一个块中(每个块有很多行),并且我可以相当有效地获取连续PK的行范围。
右。两个邻居PK值很可能在同一页面中。好吧,除了一个PK是页面中的最后一个值并且下一个PK值存储在下一页中的情况。 基本上,这就是B +树结构发明的原因。它不仅对搜索有效,而且在顺序访问方面也很有效。直到最近我们还有旋转硬盘。
MyISAM表未集群;有一些隐藏的内部行排序与PK(或任何索引)没有固定的关系,所以每当我想要获取一组行时,我可能必须为每一行检索不同的块 - 即使这些行有连续的PK。
右。如果将新记录插入MyISAM表,则无论PK顺序如何,记录都将添加到MYD文件的末尾。 MyISAM表的主索引将是B +树,其中包含指向MYD文件中记录的指针。
现在谈谈你的特殊问题。我没有看到任何理由来定义UNIQUE INDEX uq_owner_complete。
在坚持使用短的单字段索引(可能的前缀)和扩展每个索引以覆盖整个表之间是否有任何合理的中间立场?
最好的是在WHERE子句中使用的所有列上都有二级索引,除了低选择性字段(如性)。最具选择性的字段必须在索引中排在第一位。例如(last_name,eye_color)是好的。 (eye_color,last_name)很糟糕。 如果覆盖索引允许避免额外的PK查找,那就非常好。但如果不是那样的话也可以接受。
后者与在磁盘上存储整个数据集五次有什么不同,但每次都有不同的排序?
是。
将PK /代理ID添加到每个较小的索引是否有任何好处,希望查询优化器能够使用某种索引合并魔法?
PK已经是索引的一部分了。(请记住,它已经存储为数据。)因此,将PK字段显式添加到二级索引是没有意义的。我认为(但不确定)MyISAM二级索引也存储PK值(主索引存储指针)。
总结: