SQL INDEX-它是如何工作的?


19

我对数据库SQL的了解大部分是基于大学课程。无论如何,我在一家正在使用数据库的公司里呆了几个月(差不多一年)。

我读过一些书,我已经在一些培训参加有关的数据库,例如MySQLPostgreSQLSQLiteOracle和几个同样nonSQL dbS,从而我们MongoDBRedisElasticSearch等。

就像我说的那样,我是乞gg,因为他缺乏很多知识,但是今天,有人告诉了我什么,这完全违背了我的乞gg的知识。

让我解释。让我们以SQL数据库为例,创建一个Person内部表很少的简单表:

id | name   | age
-----------------
1  | Alex   | 24
2  | Brad   | 34
3  | Chris  | 29
4  | David  | 28
5  | Eric   | 18
6  | Fred   | 42
7  | Greg   | 65
8  | Hubert | 53
9  | Irvin  | 17
10 | John   | 19
11 | Karl   | 23

现在,这是我要关注的部分- idINDEX

到目前为止,我认为它是以这种方式工作的:创建表时,该表INDEX为空。当我向表中添加新记录时,INDEX正在根据一些算法重新计算。例如:

一一分组:

1    ... N
N+1  ... 2N
     ...
XN+1 ... (X+1)N

所以,我以实例size = 11 elementsN = 3这将是这样的:

id | name   | age
-----------------
1  | Alex   | 24     // group0
2  | Brad   | 34     // group0
3  | Chris  | 29     // group0
4  | David  | 28     // group1
5  | Eric   | 18     // group1
6  | Fred   | 42     // group1
7  | Greg   | 65     // group2
8  | Hubert | 53     // group2
9  | Irvin  | 17     // group2
10 | John   | 19     // group3
11 | Karl   | 23     // group3

因此,当我使用查询时SELECT * FROM Person WHERE id = 8,它将进行一些简单的计算8 / 3 = 2,因此我们必须在其中查找该对象group2,然后将返回此行:

8  | Hubert | 53

在此处输入图片说明

这种方法可以在O(k)哪里及时起作用k << size。当然,以分组方式组织行的算法肯定要复杂得多,但是我认为这个简单的示例显示了我的观点。

所以现在,我想提出另一种方法,今天已经向我展示了这种方法。

让我们再次使用此表:

id | name   | age
-----------------
1  | Alex   | 24
2  | Brad   | 34
3  | Chris  | 29
4  | David  | 28
5  | Eric   | 18
6  | Fred   | 42
7  | Greg   | 65
8  | Hubert | 53
9  | Irvin  | 17
10 | John   | 19
11 | Karl   | 23

现在,我们正在创建类似于Hashmap(实际上,它实际上是一个哈希表)的东西,该映射idaddress具有该ID的行。比方说:

id | addr 
---------
1  | @0001
2  | @0010
3  | @0011
4  | @0100
5  | @0101
6  | @0110
7  | @0111
8  | @1000
9  | @1001
10 | @1010
11 | @1011

所以现在,当我运行查询时: SELECT * FROM Person WHERE id = 8

它将直接映射id = 8到内存中的地址,并将返回该行。当然,这是复杂的O(1)

所以现在,我有几个问题。

1.两种解决方案的利弊是什么?

2.在当前的数据库实现中,哪一个最受欢迎?也许不同的数据库使用不同的方法?

3.它是否存在于非SQL数据库中?

先感谢您


比较

               |      B-tree     |   Hash Table
----------------------------------------------------
----------------   one element   -------------------
----------------------------------------------------
SEARCHING      |  O(log(N))      | O(1) -> O(N)  
DELETING       |  O(log(N))      | O(1) -> O(N)
INSERTING      |  O(log(N))      | O(1) -> O(N)
SPACE          |  O(N)           | O(N)
----------------------------------------------------
----------------    k elements   -------------------
----------------------------------------------------
SEARCHING      |  k + O(log(N))  | k * O(1) -> k * O(N)
DELETING       |  k + O(log(N))  | k * O(1) -> k * O(N)
INSERTING      |  k + O(log(N))  | k * O(1) -> k * O(N)
SPACE          |  O(N)           | O(N)

N-记录数

我对吗?每次插入/删除后重建B树哈希表的成本如何?对于B树,我们必须更改一些指针,但对于平衡B树,则需要更多的努力。同样在哈希表的情况下,我们必须要做很少的操作,特别是如果我们的操作产生冲突


2
在第二种方式中,您将描述哈希索引。关于O(1)你的部分是正确的!在第一种方式中,似乎您正在描述B树索引,但是您有一些误解。有没有计算(除以3或任何东西),这是因为树有多个级别(这是一棵树,它有大,小,小树枝,...,然后叶:)更复杂
ypercubeᵀᴹ

3
B树:en.m.wikipedia.org/wiki/B-tree惊讶有没有在你大学的算法,当然,这解释了这个
Philᵀᴹ

@ypercube嗨,谢谢您的回答。就像我写的:Of course, an alghoritm to organise rows in groups is for sure much more complicated but I think this simple example shows my point of view.当然,我知道它要复杂得多。所以最后,当我在代码INDEX中说出我的哪个解决方案(1st2nd)更接近于此实际解决方案时?而基于的访问记录所需的时间呢INDEX?是真的O(1)吗 使用B树索引听起来很像O(log2(N))。我对吗?
ruhungry 2014年

@FreshPhilOfSO我猜(我敢肯定,甚至更多)这是一些讲座。可能是我错过了一些事情……
ruhungry 2014年

ElasticSearch使用倒排索引,与B树完全不同。elastic.co/blog/found
Lluis Martinez

Answers:


12

您基本上是在描述B树索引和哈希索引。他们俩都有地方,但都最适合不同的工作。

的优点和缺点

B树(和B +树)索引通常是平衡的。这意味着无论其在树中的哪个位置,寻找一个值将始终花费相同的时间(O(log n))。通常,树中的级别数是有限的,因此它趋向于“更宽”而不是“更深”。但是,对于小型数据集,维护和使用B树的成本可能不仅仅是读取所有行。B树索引适用于大型数据集,选择性低的数据集或打算选择一系列对象而不仅仅是一个对象的数据集。

哈希表非常适合小型数据集。哈希索引具有预定义数量的哈希桶,具体取决于所使用的哈希算法。这是因为给定的哈希算法只能产生那么多唯一的哈希,因此它只会变得“更深”而不是“更广泛”。数据库引擎找到正确的存储桶后,它将遍历该存储桶中的所有对象以找到所需的对象。使用小的,高度选择性的数据集,每个存储桶都包含非常少量的对象,并且可以很快解决。随着数据集的增加,存储桶变得更加拥挤。因此,如果您需要的对象在一个较小的存储桶中或在存储桶的开头附近,它将很快返回。如果是在大桶的尽头,则需要更长的时间。索引不平衡,因此性能介于O(1)到O(n)之间。

人气度

通常,我跨B树的次数最多。位图索引也是基数较低的值(例如布尔值或性别)的另一种选择。根据可用的索引类型,这取决于数据库引擎。

NoSQL

NoSQL数据库肯定支持索引。大多数支持B树或B树的变体。大多数似乎也支持哈希索引。


4
我不认为B +树中的级别数是固定的。据我所知,至少不是在SQL Server中。
ypercubeᵀᴹ

1
确实如此。一棵B树可以有任意多个级别,但是通常限制为3或4。我编辑了答案。
sarme 2014年

嗨@sarme。我真的很喜欢你的答案。它解释了很多。您是否介意我开始对此问题悬赏?也许有人会添加一些有趣的东西。
ruhungry 2014年

1
您不是说位图索引的基数低吗?
Mihai 2014年

1
是的,低基数。我必须在上床睡觉之前停止回答问题:)。答案已更新。
sarme 2014年

4

两种解决方案都有哪些利弊?第二种解决方案无法执行范围扫描。选择单个ID非常有用。但是,如果您想要ID 3到8,该怎么办?它必须获取所有在现实世界中不仅仅是O(1)* 6条要检索的记录的个人记录。在具有HashMap索引的大型生产数据库中,您将在不同页面上获得记录,这需要您打磁盘并将六个不同的页面读入内存。

在B树结构中,就像您的第一种情况的实际实现方式一样,这些ID在磁盘上将是连续的,并且单个页面可能会容纳3-8个ID,从而提高范围扫描的速度,从而使单个访问成为O(log n) 。

在当前的数据库实现中,哪一个更受欢迎?也许不同的数据库使用不同的方法?我在许多不同的数据库中没有丰富的经验。我知道Sql Server主要使用B树,但是SQl 2014具有一些可以在某些表上使用的新哈希索引。我听到很多No Sql数据库和基于检索单个记录构建的缓存数据库也使用哈希索引。这对于缓存很有意义,因为您希望为用户A Page 11记录,并且不需要范围扫描。

它是否存在于非SQL数据库中?是。快速浏览一下postgressql的create index文档,我看到它支持Hash和B-Tree索引以及其他一些索引。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.