首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >B+tree如何处理AND、OR、IN和equals的组合?

B+tree如何处理AND、OR、IN和equals的组合?
EN

Stack Overflow用户
提问于 2021-04-30 04:13:00
回答 2查看 55关注 0票数 0

这四种类型的查询如何利用索引?扫描是什么样子的?

代码语言:javascript
复制
WHERE status = "foo"

WHERE id IN (1, 2, 3)

WHERE id IN (1, 2, 3) AND status = "foo"

WHERE id IN (1, 2, 3) OR status = "foo"

在第一种情况下,我认为这是一个以状态为键的B+tree。很简单。但是,等等,它需要在每个状态下存储多个项,所以可能它有一个数组(通常来说)记录每种状态。

但是对于第二个查询,您似乎只需要为id建立索引,并且一次从B+tree中获取每个键一个id,所以它会对每个id执行tree.get(id)。但这似乎已经不太理想了。实际上是怎么做的?

然后更进一步,结合这两种查询类型,现在只能使用其中一个索引(比如id索引,而不是status索引)。然后获得与这些ID匹配的记录子集,并遍历它们并检查状态。

现在我们开始显得效率低下。

OR查询也是如此。

一般来说,或者说,这些在数据库中是如何实现的?

我之所以问这个问题,是因为我想在JavaScript中为浏览器实现一个基本版本。基本上,最好的方法是在一个表上有多个索引(可能是多列的)。因此,我可以将记录存储在这个“表”中,它存储在每个索引中,然后在查询时从“最佳”索引中获取记录。我不太清楚这是如何在一个高层次(高层次,但在数据结构/算法实现方面非常深入)开始工作的。

这是我开始使用的模板:

代码语言:javascript
复制
class Index {
  constructor(fields = ['id']) {
    this.fields = fields
    this.tree = new Tree
  }

  insert(record) {
    this.tree.insert(this.getKey(record), block)
  }

  remove(record) {
    this.tree.remove(this.getKey(record))
  }

  check(record) {
    return this.tree.check(this.getKey(record))
  }

  getKey(record) {
    return this.fields.map(field => record[field]).join('')
  }
}

class Table {
  constructor() {
    this.index = []
  }

  insert(record) {
    this.index.forEach(index => index.insert(record))
  }

  select(query) {
    // query processing
  }

  remove(id) {
    
  }
}

因此,基本上,对于每个表,您创建了几个索引。当您插入记录时,它会获取每个索引的键,并将其插入到Tree (充当键/值存储的B+tree )中。在那里,我不知道如何正确地使用索引,也不知道我是否在正确的轨道上。我会问一个理想的关系数据库如何实现这一点,但这可能会因为过于笼统而被否决:/但这正是我真正想要构建的。

我以this B+tree为例进行工作。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-04-30 13:33:01

在您可以拥有的索引中,您似乎没有受到限制,所以让我们假设您有一个索引on (id)和一个索引on (status,id)。我还将假设id是主键或具有唯一性约束,正如id通常所做的那样:

代码语言:javascript
复制
WHERE status = "foo"

匹配状态的项的范围可以有效地从( status,id)索引中读取。

代码语言:javascript
复制
WHERE id IN (1, 2, 3)

假设id是一个整数类型,则从( id )索引中读取id >=1和<=3的项的范围。索引是有序的,找到一个连续值的范围比找到单个值更困难。

代码语言:javascript
复制
WHERE id IN (1, 2, 3) AND status = "foo"

这与(status,id)索引中的连续范围匹配。

代码语言:javascript
复制
WHERE id IN (1, 2, 3) OR status = "foo"

从(id)索引中选择(1,2,3)范围,从(status,id)索引中选择"foo“范围。然后对结果进行合并。由于两个范围都有相同顺序的不同行,因此可以像合并排序中的合并操作一样有效地合并它们。

如果希望能够使用自己的索引类执行相同的操作,则需要支持多列上的索引,并且需要能够从给定的键开始为索引中的行获取迭代器。

票数 1
EN

Stack Overflow用户

发布于 2021-12-24 17:44:51

我将针对MySQL/MariaDB专门讨论这个问题。具体情况可能因其他供应商的不同而有所不同。我已经从"1,2,3“改为”1,2,3“,以避免假定值是连续的诱惑。我也改变了"id“,因为idPRIMARY KEY

MySQL将使用B+Tree。

代码语言:javascript
复制
WHERE status = "foo"
    INDEX(status)       -- best
    INDEX(status, ...)  -- nearly as good
    If a nontrivial number of rows have "foo", it won't bother using any index!

WHERE bar IN (123, 456, 789)
    INDEX(bar)  -- It will do multiple BTree lookups.

WHERE bar IN (123, 456, 789) AND status = "foo"
    INDEX(status, bar)   -- In this order

WHERE bar IN (123, 456, 789) OR status = "foo"
    No index is likely to be beneficial; it will do a table scan.
    It would probably run faster to use two SELECTs and a UNION

如果您需要执行所有4个查询,那么我建议您使用以下两个索引:

代码语言:javascript
复制
    INDEX(status, bar)  -- helps 1st and 3rd
    INDEX(bar)          -- helps 2nd

考虑将这些列连接起来,然后将其用作BTree中的一个键。(这将使您不会因单个列的“基数”或“选择性”而分心。)

这没有涉及到“聚类”和“索引合并”和许多其他主题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67328091

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档