数据库索引如何工作? [关闭]
关闭。这个问题需要更加集中。它目前不接受答案。想改进这个问题?更新问题,使其仅通过编辑此帖子专注于一个问题。 4个月前关闭。社区在 4 个月前审查了是否重新打开此问题并将其关闭:原始关闭原因未解决 改进此问题鉴于索引随着数据集大小的增加而变得如此重要,有人可以解释索引如何在与数据库无关的级别上工作吗?有关为字段编制索引的查询的信息,请查看 How do I index a database col
问:
关闭。这个问题需要更加集中。它目前不接受答案。想改进这个问题?更新问题,使其仅通过编辑此帖子专注于一个问题。 4个月前关闭。社区在 4 个月前审查了是否重新打开此问题并将其关闭:原始关闭原因未解决 改进此问题
鉴于索引随着数据集大小的增加而变得如此重要,有人可以解释索引如何在与数据库无关的级别上工作吗?
有关为字段编制索引的查询的信息,请查看 How do I index a database column。
答1:
HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com
为什么需要它?
当数据存储在基于磁盘的存储设备上时,它被存储为数据块。这些块被完整地访问,使它们成为原子磁盘访问操作。磁盘块的结构与链表非常相似;两者都包含一个数据部分,一个指向下一个节点(或块)位置的指针,并且两者都不需要连续存储。
由于许多记录只能在一个字段上排序,我们可以说在未排序的字段上搜索需要线性搜索,这需要 (N+1)/2 块访问(平均),其中 N是表跨越的块数。如果该字段是非键字段(即不包含唯一条目),则必须在 N 块访问时搜索整个表空间。
而对于排序字段,可以使用具有 log2 N 块访问的二进制搜索。此外,由于数据是在给定非关键字段的情况下排序的,因此一旦找到更高的值,就不需要在表的其余部分搜索重复值。因此,性能提升是可观的。
什么是索引?
索引是一种对多个字段上的许多记录进行排序的方法。在表中的字段上创建索引会创建另一个数据结构,该结构包含字段值和指向与其相关的记录的指针。然后对该索引结构进行排序,允许对其执行二进制搜索。
索引的缺点是这些索引需要额外的磁盘空间,因为索引使用 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 = 5,000,000 固定大小记录的示例数据库,记录长度为 R = 204 字节,并且它们使用 MyISAM 引擎存储在表中,该引擎使用默认块大小 B = 1,024 字节。表的阻塞因子是每个磁盘块 bfr = (B/R) = 1024/204 = 5 条记录。保存该表所需的块总数为 N = (r/bfr) = 5000000/5 = 1,000,000 个块。
鉴于 id 字段是关键字段,对 id 字段进行线性搜索需要平均 N/2 = 500,000 次块访问才能找到值。但由于 id 字段也已排序,因此可以进行二进制搜索,平均需要 log2 1000000 = 19.93 = 20 个块访问。立即我们可以看到这是一个巨大的改进。
现在 firstName 字段既不是排序的也不是键字段,因此不可能进行二分搜索,值也不是唯一的,因此该表将需要搜索到最后以获取精确的 N = 1,000,000 块访问.索引旨在纠正这种情况。
鉴于索引记录仅包含索引字段和指向原始记录的指针,因此按道理它会小于它所指向的多字段记录。所以索引本身比原始表需要更少的磁盘块,因此需要更少的块访问来迭代。 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 = 5,000,000 记录示例数据库,索引记录长度为 R = 54 字节并使用默认块大小 B = 1,024 字节。索引的阻塞因子是每个磁盘块 bfr = (B/R) = 1024/54 = 18 条记录。保存索引所需的块总数为 N = (r/bfr) = 5000000/18 = 277,778 个块。
现在使用 firstName 字段的搜索可以利用索引来提高性能。这允许使用平均 log2 277778 = 18.08 = 19 块访问对索引进行二进制搜索。要找到实际记录的地址,这需要进一步的块访问才能读取,使总数达到 19 + 1 = 20 个块访问,与在非索引表。
什么时候应该使用它?
鉴于创建索引需要额外的磁盘空间(从上面的示例中额外增加了 277,778 个块,增加了约 28%),并且索引过多会导致文件系统大小限制引起的问题,因此必须仔细考虑选择正确的要索引的字段。
由于索引仅用于加快在记录中搜索匹配字段的速度,因此按理说,仅用于输出的索引字段在执行插入或删除操作时只会浪费磁盘空间和处理时间,因此应该避免。同样考虑到二分搜索的性质,数据的基数或唯一性也很重要。对基数为 2 的字段进行索引会将数据分成两半,而基数为 1,000 的字段将返回大约 1,000 条记录。在如此低的基数下,效率降低为线性排序,如果基数小于记录数的 30%,查询优化器将避免使用索引,从而有效地使索引浪费空间。
当数据唯一时可以进行二进制搜索,对吗?尽管您提到最小基数很重要,但该算法不会是简单的二进制搜索,这种近似值(〜log2 n)将如何影响处理时间?
@AbhishekShivkumar:好问题!我认为索引表的行数与数据表中的行数一样多。由于该字段只有 2 个值(布尔值,true/false)& 说你想要一个值为 true 的记录,那么你只能在第一遍中将结果集减半,在第二遍中,所有记录的值为 true,所以有没有区分的基础,现在您必须以线性方式搜索数据表 - 因此他说在确定索引列时应考虑基数。在这种情况下,对这样的列进行索引是毫无价值的。希望我是对的:)
平均情况下的块访问数不应该是 (N+1)/2。如果我们将所有可能情况的块访问次数相加,然后将其除以情况数,那么我们有 N*(N+1)/(2*n),即 (N+1)/2。
我认为这个答案有一些错别字,例如,在句子中:“与非索引表所需的 277,778 块访问相去甚远。”作者的意思不是 1,000,000 块访问吗? 277,778 是索引本身所需的块数。似乎还有其他一些不准确之处:(
@jcm他在“什么是索引部分”中解释了它-“索引是一种对多个字段上的许多记录进行排序的方法。在表中的字段上创建索引会创建另一个保存字段值和指针的数据结构“
答2:
huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式
经典示例“书籍索引”
考虑一本 1000 页的“书”,除以 10 个章节,每个章节有 100 页。
很简单吧?
现在,假设您要查找包含“Alchemist”一词的特定章节。如果没有索引页,除了浏览整本书/章节之外,您别无选择。即:1000 页。
这个类比在数据库世界中被称为“全表扫描”。
https://i.stack.imgur.com/Mnuvr.jpg
但是有了索引页面,您就知道该去哪里了!而且,要查找任何重要的特定章节,您只需要一次又一次地查看索引页面。找到匹配索引后,您可以通过跳过其余部分有效地跳到该章节。
但是,除了实际的 1000 页之外,您还需要大约 10 页来显示索引,因此总共需要 1010 页。
因此,索引是一个单独的部分,它按排序顺序存储索引列的值 + 指向索引行的指针,以实现高效查找。
学校里的事情很简单,不是吗? 😛
真的很好的比喻!有趣的是我没有在书索引和数据库索引之间建立联系
这让我想到 Library 或 Grocery Store 你能想象在杂货店没有索引吗? Where's The Beef?!? Oh its next to the Restrooms, a mop, and makeup
“但开头有一个索引页,你就在那里。” “你在那里”是什么意思?
索引通常放在书的后面,而目录放在前面。但是,这使得类比更好,因为列顺序无关紧要。
我仍然不完全理解,所以如果有 n 个唯一词,索引将如何帮助我?它为每个单词创建指针?如果是这样,甚至可能在同一时间找到该指针需要花费大量时间,然后只需滚动所有内容并以默认方式找到它
答3:
huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。
索引只是一种数据结构,它使搜索数据库中特定列的速度更快。这种结构通常是 b 树或哈希表,但也可以是任何其他逻辑结构。
为这个答案+一百万倍,因为我在试图找到索引本质上是什么的简单解释时发现了这个清单。
请注意,“只是一个数据结构”并不意味着“附加到数据”。有时它是(例如“非聚集索引”),有时它决定了数据的布局(例如“聚集索引”)。
这是最好的答案,索引基本上就像一个 Hashmap,其中 get 具有 O(1) 复杂性,而在 List 中搜索是 O(N)
答4:
HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com
第一次读到这篇文章对我很有帮助。谢谢你。
从那时起,我对创建索引的缺点有了一些了解:如果您使用一个索引写入表(UPDATE 或 INSERT),那么您实际上在文件系统中有两个写入操作。一个用于表数据,另一个用于索引数据(以及对它的重新排序(以及 - 如果聚集 - 对表数据进行重新排序))。如果表和索引位于同一个硬盘上,这将花费更多时间。因此,没有索引(堆)的表将允许更快的写入操作。 (如果你有两个索引,你最终会得到三个写操作,依此类推)
然而,在两个不同的硬盘上为索引数据和表数据定义两个不同的位置可以减少/消除时间成本增加的问题。这需要在所需硬盘上定义具有相应文件的附加文件组,并根据需要定义表/索引位置。
索引的另一个问题是随着数据的插入,它们会随着时间的推移而产生碎片。 REORGANIZE 有帮助,您必须编写例程才能完成。
在某些情况下,堆比带有索引的表更有帮助,
例如:- 如果您有很多相互竞争的写入,但在工作时间之外只有一个夜间阅读用于报告。
此外,聚集索引和非聚集索引之间的区别非常重要。
帮助了我:- What do Clustered and Non clustered index actually mean?
huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。
我认为,这些索引问题可以通过维护两个不同的数据库来解决,就像 Master 和 Slave。其中 Master 可用于插入或更新记录。没有索引。而且slave可以用来读取正确的索引???
不,错,对不起。不仅表的内容必须更新,而且索引结构和内容(b-tree、节点)也必须更新。你的主人和奴隶的概念在这里没有意义。可行的方法是复制或镜像到第二个数据库,在该数据库上进行分析以从第一个数据库中移除该工作负载。第二个数据库将保存该数据的数据副本和索引。
耶……!尝试阅读我的评论并正确理解它。我也说过同样的话,我将主从(无论如何)称为“复制或镜像到第二个数据库,在该数据库上进行分析以将工作负载从第一个数据库中移除。第二个数据库将保存数据和索引的副本那个数据”
第二个数据库 - 已完成镜像或复制的从属数据库 - 将像第一个数据库一样经历所有数据操作。对于每个 dml 操作,第二个数据库上的索引都会遇到“这些索引问题”。我没有看到其中的好处,无论何时需要索引并为快速分析而构建它们都需要保持最新。
答5:
huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!
现在,假设我们要运行一个查询来查找任何名为“Abc”的员工的所有详细信息?
SELECT * FROM Employee
WHERE Employee_Name = 'Abc'
没有索引会怎样?
数据库软件实际上必须查看 Employee 表中的每一行,以查看该行的 Employee_Name 是否为“Abc”。而且,因为我们想要其中的每一行名称为“Abc”,所以一旦我们只找到一个名称为“Abc”的行,我们就不能停止查找,因为可能还有其他行名称为 Abc。因此,必须搜索直到最后一行的每一行——这意味着在这种情况下,数据库必须检查数千行才能找到名称为“Abc”的行。这就是所谓的全表扫描
数据库索引如何帮助提高性能
拥有索引的全部意义在于通过减少表中需要检查的记录/行数来加速搜索查询。索引是一种数据结构(最常见的是 B 树),用于存储表中特定列的值。
B树索引如何工作?
B-树是最流行的索引数据结构的原因是因为它们具有时间效率——因为查找、删除和插入都可以在对数时间内完成。而且,B-tree 更常用的另一个主要原因是因为存储在 B-tree 中的数据可以排序。 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 列上确实创建了索引,数据库将不得不决定使用索引来查找正在搜索的值是否真的有意义——因为在某些情况下使用数据库索引实际上效率较低,并且更高效地只扫描整个表。
拥有数据库索引的成本是多少?
它占用空间——而且你的表越大,你的索引就越大。索引的另一个性能问题是,无论何时添加、删除或更新相应表中的行,都必须对索引执行相同的操作。请记住,索引需要包含与索引所涵盖的表列中的任何内容相同的最新数据。
作为一般规则,只有当索引列中的数据将被频繁查询时,才应在表上创建索引。
也可以看看
哪些列通常可以制作好的索引?数据库索引如何工作
“数据库索引不存储其他列中的值” - 不正确。
@mustaccio:索引仅存储带有索引列的行引用(据我所知)。我可能错了。你有没有说索引存储其他列值的参考?
@To Downvoters:你能解释一下哪里出了问题,以便我改进吗?
检查例如 SQL Server 集群索引或 DB2 的 CREATE INDEX ... INCLUDE 子句。在我看来,你的回答中有太多的概括。
@mustaccio:所以默认情况下 create index 不包括其他列以及为什么应该包含。 If we did just store all the other columns in the index, then it would be just like creating another copy of the entire table, which would take up way too much space and would be very inefficient.。这是更通用的索引版本。 CREATE INDEX ... INCLUDE 是考虑其他列的较新版本。我已经解释过的帖子正在考虑更通用的版本。如果我们考虑所有数据库,索引如何工作将是一本书?不是吗?您认为答案值得否决吗?
答6:
huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。
简单说明!
索引只不过是一种数据结构,用于存储表中特定列的值。索引是在表的列上创建的。
示例:我们有一个名为 User 的数据库表,其中包含三列 - Name、Age 和 Address。假设 User 表有数千行。
现在,假设我们要运行一个查询来查找名为“John”的任何用户的所有详细信息。如果我们运行以下查询:
SELECT * FROM User
WHERE Name = 'John'
数据库软件实际上必须查看 User 表中的每一行,以查看该行的 Name 是否为“John”。这将需要很长时间。
这就是 index 可以帮助我们的地方:索引用于通过从本质上减少表中需要检查的记录/行数来加速搜索查询。
如何创建索引:
CREATE INDEX name_index
ON User (Name)
index 由一个表中的列值(例如:John) 组成,这些值存储在 数据结构 中。
因此,现在数据库将使用索引来查找名为 John 的员工,因为该索引可能会按用户名称的字母顺序排序。而且,因为它是排序的,这意味着搜索名称要快得多,因为所有以“J”开头的名称将在索引中彼此相邻!
索引并不意味着列上的排序顺序
谢谢。这有助于我的理解。所以基本上索引是已排序的列数据的副本。通常,列数据只是按照插入数据的顺序排列。
这是否意味着在内部,为每个名称维护一个单独的表,例如 Name=John 有它自己的表
“索引只不过是一种数据结构,用于存储表中特定列的值”——为什么这么说?我认为价值还不够;相反,它必须在表中存储对行/记录的引用。如果我有一个包含 10 列的表,其中之一是 COUNTRY_CODE,则索引不能只存储 COUNTRY_CODE 的值,它必须存储对表行的引用。否则,如果您对另一列执行 SELECT 但在 COUNTRY_CODE 上加入/选择,您将无法单独使用 COUNTRY_CODE 值。
答7:
huntsbot.com洞察每一个产品背后的需求与收益,从而捕获灵感
只需将数据库索引视为一本书的索引。
如果你有一本关于狗的书,并且你想找到关于德国牧羊犬的信息,你当然可以翻阅这本书的所有页面并找到你要找的东西——但这当然很耗时,而且不会非常快。
另一种选择是,您可以转到本书的索引部分,然后使用您正在查找的实体的名称(在本例中为德国牧羊犬)并查看页码来查找您要查找的内容快速找到您要查找的内容。
在数据库中,页码被称为一个指针,它将数据库指向实体所在的磁盘上的地址。使用相同的德国牧羊犬类比,我们可以有这样的东西(“德国牧羊犬”,0x77129),其中 0x77129 是磁盘上存储德国牧羊犬行数据的地址。
简而言之,索引是一种数据结构,用于存储表中特定列的值,以加快查询搜索速度。
原文链接:https://www.huntsbot.com/qa/lavj/how-does-database-indexing-work?lang=zh_CN&from=csdn
huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。
更多推荐
所有评论(0)