超过1列的B树索引是什么样的?

时间:2009-10-30 05:52:57

标签: sql-server database oracle indexing

所以我正在阅读索引及其实现,我偶然发现了这个简短解释b-tree索引的网站:

http://20bits.com/articles/interview-questions-database-indexes/

b-tree索引对于仅在单个列上的索引非常有意义,但是假设我创建了一个包含多列的索引,那么b-tree如何工作呢? b树中每个节点的价值是多少?

例如,如果我有这个表:

table customer:
id    number
name   varchar
phone_number   varchar
city   varchar

我在:(id,name,city)

上创建索引

然后运行以下查询:

SELECT id, name 
  FROM customer
 WHERE city = 'My City';

此查询如何使用多列索引,或者除非将索引创建为(city,id,name)或(city,name,id),否则它不会使用它?

6 个答案:

答案 0 :(得分:15)

对于大多数实现,密钥只是一个包含所有键值的较长键,带有分隔符。没有魔法; - )

在您的示例中,键值可能类似于

"123499|John Doe|Conway, NH"
"32144|Bill Gates| Seattle, WA"

使用复合键的这些索引的一个特征是,在某些情况下可以使用中间树节点来“覆盖”查询。

例如,如果查询要查找给定ID的名称和城市,由于ID在索引中是第一个,因此索引可以有效地搜索。一旦进入中间节点,它就可以从密钥“解析”Name和City,而不需要去叶子节点读取它。

但是,如果查询还想显示电话号码,那么当找到完整记录时,逻辑将跟随叶子。

答案 1 :(得分:11)

想象一下,密钥由Python元组(col1,col2,col3)表示......索引操作涉及将tuple_atuple_b进行比较...如果您不知道哪个您感兴趣的col1和col2的值,但只有col3,那么它必须读取整个索引(“完整索引扫描”),这不是那么有效。

如果你有一个索引(col1,col2,col3),那么当WHERE子句包含对(1)所有3列(2)的引用时,你可以预期任何RDBMS将使用索引(以直接的方式) col1和col2(3)都只有col1。

否则(例如,WHERE子句中只有col3),RDBMS根本不会使用该索引(例如SQLite),或者将执行完整的索引扫描(例如Oracle)[如果没有其他索引更好]。 / p>

在您的具体示例中,假设id是客户的唯一标识符,将其显示在索引中是没有意义的(除了DBMS应为主键或列标记为UNIQUE设置的索引之外)

答案 2 :(得分:3)

有些实现只是按照列的顺序连接值,并带有分隔符。

另一种解决方案是在b树中简单地使用b树。当您点击第一列的叶子时,您将获得匹配记录的列表和下一列的迷你b树,依此类推。因此,索引中指定的列的顺序对该索引是否对特定查询有用产生巨大差异。

这是我上周写的相关问题:

Does SQL Server jump leaves when using a composite clustered index?

答案 3 :(得分:2)

在Oracle中,即使未过滤前导列,也可以使用复合键索引。这是通过三种机制完成的:

  1. 快速全索引扫描,其中多块读取用于遍历整个索引段。
  2. 索引全扫描,其中索引按块的逻辑顺序读取(我相信我读过在最近的版本中,Oracle可以使用多块读取,但实际上你应该指望单块读取)
  3. inddex跳过扫描,其中非谓词前导列的基数非常低,允许Oracle执行多个索引范围扫描,一个用于前导列的每个唯一值。根据我的经验,这些非常罕见。
  4. 查看Richard Foote或Jonathan Lewis的文章,了解有关Oracle索引内部的更多信息。

答案 4 :(得分:0)

除了已经描述的“复合密钥”机制之外,一种可能性是kdtree,其工作方式类似于二叉树,但当您遍历每个级别时,您将循环遍历k维度。也就是说,树的第一级将第一维分成两部分,第二级将第二维分开,第k+1级再次分割第一维,等等。这样可以有效地划分数据。任意数量的尺寸。这种方法在“空间”数据库(例如,Oracle Spatial,PostGIS等)中很常见,但在“常规”多索引表中可能不那么有用。

http://en.wikipedia.org/wiki/Kd-tree

答案 5 :(得分:0)

它可以使用(id,name,city)索引来满足“City =?”谓词,但非常非常无效。

为了使用索引来满足此查询,它需要遍历大部分树结构,以查找具有所需城市的条目。这仍然可能比扫描桌子的速度更快!

(city,name,id)的索引将是您查询的最佳索引。它可以轻松找到所有想要的城市条目,并且不需要访问基础表来获取id和名称值。