簡體   English   中英

B+tree 如何處理 AND、OR、IN 和 equals 的組合?

[英]How does a B+tree handle a combination of AND, OR, IN and equals?

這 4 種查詢如何利用索引? 掃描結果如何?

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+樹,關鍵是狀態。 很容易。 但是等等,它需要為每個狀態存儲多個項目,所以它可能有一個數組(一般來說)每個狀態的記錄。

但是對於第二個查詢,您似乎只需將索引設置為id並從 B+tree 中一次獲取一個id的每個鍵,因此它會為每個id執行tree.get(id) 但這似乎已經不太理想了。 它實際上是如何完成的?

然后再進一步結合這兩種查詢類型,你現在只能使用其中一種索引(比如id索引,而不是status索引)。 然后,您獲取與這些 ID 匹配的記錄子集,並遍歷它們並檢查狀態。

現在我們開始顯得效率低下。

與 OR 查詢相同。

一般來說或理想情況下,這些通常如何在數據庫中實現?

我問是因為我想在 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+樹)。 從那里我不知道如何正確使用索引,或者我是否在正確的軌道上。 我會問一個理想的關系數據庫將如何實現這一點,但這可能會因為過於籠統而被否決:/但這正是我真正想要構建的。

我以這個 B+tree為例。

您似乎沒有受到可以擁有的索引的限制,因此假設您在 (id) 上有一個索引,在 (status, id) 上有一個索引。 我還將假設 id 是主鍵或具有唯一性約束,就像 ID 通常那樣:

WHERE status = "foo"

從 (status,id) 索引中有效地讀取與狀態匹配的項目范圍。

WHERE id IN (1, 2, 3)

假設 id 是整數類型,則從 (id) 索引中讀取 id >=1 和 <=3 的項目范圍。 索引是有序的,查找一系列連續值並不比查找單個值難。

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

這匹配 (status, id) 索引中的連續范圍。

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

(1,2,3) 范圍是從 (id) 索引中選擇的,“foo”范圍是從 (status, id) 索引中選擇的。 然后合並結果。 由於兩個范圍具有相同順序的不同行,因此可以像合並排序中的合並操作一樣有效地合並它們。


如果你想用你自己的索引 class 做同樣的事情,你需要支持多列的索引,你需要能夠從給定的鍵開始獲取索引中行的迭代器.

我將專門針對 MySQL/MariaDB 解決這個問題。 具體情況可能因其他供應商而異。 我已經改變了“1,2,3”以避免假設這些值是連續的。 我也改變了“id”,因為idPRIMARY KEY

MySQL 將使用 B+樹。

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 個查詢,那么我建議您使用以下兩個索引:

    INDEX(status, bar)  -- helps 1st and 3rd
    INDEX(bar)          -- helps 2nd

考慮連接列,然后將其用作 BTree 的單個鍵。 (這將使您不會因各個列的“基數”或“選擇性”而分心。)

這不涉及“集群”和“索引合並”等許多主題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM