鉴于随着数据集大小的增加,索引变得如此重要,有人能解释一下索引是如何在数据库不可知的级别上工作的吗?
有关对字段进行索引的查询的信息,请查看How do I index a database column。
鉴于随着数据集大小的增加,索引变得如此重要,有人能解释一下索引是如何在数据库不可知的级别上工作的吗?
有关对字段进行索引的查询的信息,请查看How do I index a database column。
为什么需要它?
当数据存储在基于磁盘的存储设备上时,它被存储为数据块。这些块被完整地访问,使它们成为原子磁盘访问操作。磁盘块的结构与链接列表几乎相同;两者都包含一个数据段,一个指向下一个节点(或块)位置的指针,两者不需要连续存储。
由于许多记录只能在一个字段上排序,我们可以声明,在未排序的字段上进行搜索需要线性搜索,该搜索需要(平均)(N+1)/2个块访问,其中N是表跨越的块数。如果该字段是非关键字字段(即不包含唯一条目),则必须在N次块访问时搜索整个表空间。
而对于排序字段,可以使用二进制搜索,它具有log2N个块访问。此外,由于数据是在给定非关键字字段的情况下排序的,因此一旦找到更高的值,就不需要搜索表的其余部分以查找重复值。因此,性能大幅提高。
什么是索引?
索引是对多个字段上的多个记录进行排序的一种方法。在表中的字段上创建索引将创建另一个数据结构,该数据结构保存字段值和指向与字段值相关的记录的指针。然后对该索引结构进行排序,允许对其执行二进制搜索。
索引的缺点是,这些索引需要额外的磁盘空间,因为索引使用MyISAM引擎一起存储在一个表中。如果对同一表中的许多字段进行索引,则该文件可以很快达到基础文件系统的大小限制。
它是如何工作的?
首先,让我们概述一个示例数据库表模式;
Field name Data type Size on disk id (Primary key) Unsigned INT 4 bytes firstName Char(50) 50 bytes lastName Char(50) 50 bytes emailAddress Char(100) 100 bytes
注意:使用了char代替varchar,以获得准确的磁盘大小值。此示例数据库包含500万行,未编制索引。现在将分析几个查询的性能。这是一个使用id的查询(一个排序的关键字字段)和一个使用firstName的查询(非关键字的未排序字段)。
示例1-排序字段与未排序字段
给定我们的示例数据库,r=5000000条固定大小的记录,记录长度为r=204字节,它们使用MyISAM引擎存储在表中,该引擎使用默认的块大小B=1024字节。表的阻塞因子为bfr=(B/R)=1024/204=每个磁盘块5条记录。保存表格所需的块总数为N=(r/bfr)=5000000/5=1000000个块。
如果id字段是关键字字段,则对id字段进行线性搜索将需要平均N/2=500000次块访问才能找到值。但是,由于id字段也被排序,因此可以进行二进制搜索,平均需要log2 1000000=19.93=20个块访问。我们马上就能看到这是一个巨大的进步。
现在firstName字段既不是排序字段,也不是关键字字段,因此二进制搜索是不可能的,值也不是唯一的,因此表将需要搜索到底,以获得精确的N=1000000个块访问。索引旨在纠正这种情况。
由于索引记录只包含索引字段和指向原始记录的指针,因此它将比它所指向的多字段记录小。因此,索引本身需要的磁盘块比原始表少,因此需要更少的块访问来进行迭代。firstName字段上索引的模式概述如下:;
Field name Data type Size on disk firstName Char(50) 50 bytes (record pointer) Special 4 bytes
注意:MySQL中的指针长度为2、3、4或5字节,具体取决于表的大小。
示例2-索引
给定我们的示例数据库,r=5000000条记录,索引记录长度r=54字节,使用默认块大小B=1024字节。索引的阻塞因子为bfr=(B/R)=1024/54=18条记录/磁盘块。保持索引所需的块总数为N=(r/bfr)=5000000/18=277778个块。
现在,使用firstName字段的搜索可以利用索引来提高性能。这允许索引的二进制搜索,平均log2 277778=18.08=19个块访问。为了找到实际记录的地址,这需要进一步的块访问才能读取,使总访问量达到19+1=20个块,这与在非索引表中查找firstName匹配所需的1000000个块访问量相去甚远。
何时使用?
考虑到创建索引需要额外的磁盘空间(与上面的示例相比,增加了277778个块,增加了约28%),而且索引过多会导致文件系统大小限制引起的问题,因此必须仔细考虑选择要索引的正确字段。
由于索引仅用于加快在记录中搜索匹配字段的速度,因此在执行插入或删除操作时,仅用于输出的索引字段只会浪费磁盘空间和处理时间,因此应该避免。此外,考虑到二进制搜索的性质,数据的基数或唯一性也很重要。对基数为2的字段进行索引将数据一分为二,而基数为1000将返回大约1000条记录。使用如此低的基数,效率降低到线性排序,如果基数小于记录数的30%,查询优化器将避免使用索引,从而有效地使索引浪费空间。
我第一次读到这篇文章时,它对我很有帮助。谢谢。
从那以后,我对创建索引的缺点有了一些见解:如果用一个索引写入表(UPDATE或INSERT),那么文件系统中实际上有两个写入操作。一个用于表数据,另一个用于索引数据(以及它的重新排序(如果是集群的话,还包括表数据的重新排序))。如果表和索引位于同一硬盘上,这将花费更多的时间。因此,没有索引的表(堆)将允许更快的写入操作。(如果您有两个索引,那么最终将有三个写操作,依此类推)
然而,在两个不同的硬盘上为索引数据和表数据定义两个不同位置可以减少/消除时间成本增加的问题。这需要根据所需硬盘上的文件定义其他文件组,并根据需要定义表/索引位置。
索引的另一个问题是,在插入数据时,索引会随着时间的推移而碎片化。重新组织有帮助,您必须编写例程才能完成。
在某些情况下,堆比具有索引的表更有用,
例如:-如果你有很多竞争性的写作,但只有一个晚上在工作时间外阅读报告。
此外,区分聚集索引和非聚集索引非常重要。
帮助我:-聚集索引和非聚集索引实际上是什么意思?
简单描述!
索引只是一个数据结构,它存储表中特定列的值。在表的列上创建索引。
示例:我们有一个名为User的数据库表,其中有三列:Name、Age和Address。假设User表有数千行。
现在,假设我们想运行一个查询来查找任何名为“John”的用户的所有详细信息。如果我们运行以下查询:
SELECT * FROM User
WHERE Name = 'John'
数据库软件实际上必须查看User表中的每一行,以查看该行的名称是否为“John”。这需要很长时间。
这就是索引帮助我们的地方:索引用于通过实质上减少表中需要检查的记录/行的数量来加快搜索查询。
如何创建索引:
CREATE INDEX name_index
ON User (Name)
索引由一个表中的列值(例如:John)组成,这些值存储在数据结构中。
所以现在数据库将使用索引查找名为John的员工因为索引将按用户名。而且,因为它是排序的,所以它意味着搜索名称因为所有以“J”开头的名字都是正确的在索引中彼此相邻!
现在,假设我们想运行一个查询来查找任何名为“Abc”的员工的所有详细信息?
SELECT * FROM Employee
WHERE Employee_Name = 'Abc'
没有索引会发生什么?
数据库软件实际上必须查看Employee表中的每一行,以查看该行的Employee_Name是否为“Abc”。而且,因为我们希望每一行都包含名为“Abc”的行,所以当我们找到一行名为“Abc”时,我们不能停止查找,因为可能还有其他行名为Abc。因此,必须搜索直到最后一行的每一行,这意味着数据库必须检查此场景中的数千行,以查找名为“Abc”的行。这就是所谓的全表扫描
数据库索引如何提高性能
拥有索引的全部目的是通过实质上减少表中需要检查的记录/行的数量来加快搜索查询。索引是一种数据结构(最常见的是B树),用于存储表中特定列的值。
B树索引是如何工作的?
B树之所以是索引最流行的数据结构,是因为它们具有时间效率——因为查找、删除和插入都可以在对数时间内完成。另外,B树更常用的另一个主要原因是,存储在B树中的数据可以被排序。RDBMS通常确定索引实际使用的数据结构。但是,在某些特定RDBMS的场景中,您实际上可以指定在创建索引本身时希望数据库使用的数据结构。
哈希表索引是如何工作的?
之所以使用哈希索引,是因为哈希表在查找值时非常有效。因此,如果使用哈希索引,比较字符串是否相等的查询可以非常快速地检索值。
例如,我们前面讨论的查询可以从Employee_Name列上创建的哈希索引中受益。哈希索引的工作方式是,列值将是哈希表的键,映射到该键的实际值将只是指向表中行数据的指针。由于哈希表基本上是关联数组,一个典型的条目看起来像“Abc=>0x28939”,其中0x28939是对内存中存储Abc的表行的引用。在哈希表索引中查找类似“Abc”的值并在内存中获取对该行的引用显然比扫描表以查找Employee_Name列中值为“Abc“的所有行快得多。
哈希索引的缺点
哈希表不是经过排序的数据结构,有许多类型的查询哈希索引甚至无法帮助处理。例如,假设你想找出所有不到40岁的员工。你怎么能用哈希表索引做到这一点?嗯,这是不可能的,因为哈希表只适用于查找键值对——这意味着查询可以检查是否相等
数据库索引中到底是什么?因此,现在您知道数据库索引是在表中的列上创建的,并且索引将值存储在该特定列中。但是,重要的是要了解数据库索引不会将值存储在同一表的其他列中。例如,如果我们在Employee_Name列上创建索引,这意味着Employee_Age和Employee.Address列值也不会存储在索引中。如果我们只是将所有其他列存储在索引中,那么这就像创建整个表的另一个副本一样——这会占用太多空间,而且效率很低。
数据库如何知道何时使用索引?当运行类似“SELECT*FROM Employee WHERE Employee_Name='Abc'”的查询时,数据库将检查正在查询的列上是否有索引。假设Employee_Name列上确实创建了索引,则数据库必须决定使用索引来查找所搜索的值是否有意义,因为在某些情况下,使用数据库索引实际上效率较低,而仅扫描整个表效率更高。
拥有数据库索引的成本是多少?
它会占用空间,而且表越大,索引就越大。索引对性能的另一个影响是,无论何时添加、删除或更新相应表中的行,都必须对索引执行相同的操作。请记住,索引需要包含与索引所覆盖的表列中的数据相同的最新数据。
通常,只有在索引列中的数据将被频繁查询的情况下,才应该在表上创建索引。
另请参见
哪些列通常是好索引?数据库索引如何工作
只需将数据库索引视为一本书的索引即可。
如果你有一本关于狗的书,你想找到关于德国牧羊犬的信息,你当然可以翻遍这本书的所有页面,找到你想要的东西——但这当然很耗时,而且速度也不快。
另一种选择是,你可以直接进入书中的索引部分,然后通过使用你要查找的实体的名称(在本例中为德国牧羊犬)并查看页码来快速查找你要查找什么。
在数据库中,页码被称为指针,它将数据库指向实体所在磁盘上的地址。使用同样的德国牧羊犬类比,我们可以得到类似的结果(“德国牧羊犬”,0x77129),其中0x77129是存储德国牧羊犬行数据的磁盘上的地址。
简而言之,索引是一种数据结构,它存储表中特定列的值,以加快查询搜索速度。
经典示例“图书索引”
考虑一本1000页的“书”,分为10章,每节100页。
简单,嗯?
现在,假设你想找到一个包含“炼金术士”一词的特定章节。如果没有索引页,除了扫描整本书/章节,你别无选择。即:1000页。
这种类比在数据库世界中被称为“全表扫描”。
但是有了索引页,你就知道该去哪里了!此外,要查找任何重要的特定章节,您只需反复查看索引页即可。找到匹配的索引后,可以跳过其余部分,高效地跳转到该章节。
但是,除了实际的1000页之外,您还需要大约10页来显示索引,因此总共需要1010页。
因此,索引是一个单独的部分,存储索引的值列+按排序顺序指向索引行的指针,以提高效率查找。
学校里的事情很简单,不是吗P