所以我正在阅读索引及其实现,我偶然发现了这个简短解释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),否则它不会使用它?
答案 0 :(得分:15)
对于大多数实现,密钥只是一个包含所有键值的较长键,带有分隔符。没有魔法; - )
在您的示例中,键值可能类似于
"123499|John Doe|Conway, NH" "32144|Bill Gates| Seattle, WA"
使用复合键的这些索引的一个特征是,在某些情况下可以使用中间树节点来“覆盖”查询。
例如,如果查询要查找给定ID的名称和城市,由于ID在索引中是第一个,因此索引可以有效地搜索。一旦进入中间节点,它就可以从密钥“解析”Name和City,而不需要去叶子节点读取它。
但是,如果查询还想显示电话号码,那么当找到完整记录时,逻辑将跟随叶子。
答案 1 :(得分:11)
想象一下,密钥由Python元组(col1,col2,col3)表示......索引操作涉及将tuple_a
与tuple_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中,即使未过滤前导列,也可以使用复合键索引。这是通过三种机制完成的:
查看Richard Foote或Jonathan Lewis的文章,了解有关Oracle索引内部的更多信息。
答案 4 :(得分:0)
除了已经描述的“复合密钥”机制之外,一种可能性是kdtree
,其工作方式类似于二叉树,但当您遍历每个级别时,您将循环遍历k
维度。也就是说,树的第一级将第一维分成两部分,第二级将第二维分开,第k+1
级再次分割第一维,等等。这样可以有效地划分数据。任意数量的尺寸。这种方法在“空间”数据库(例如,Oracle Spatial,PostGIS等)中很常见,但在“常规”多索引表中可能不那么有用。
答案 5 :(得分:0)
它可以使用(id,name,city)索引来满足“City =?”谓词,但非常非常无效。
为了使用索引来满足此查询,它需要遍历大部分树结构,以查找具有所需城市的条目。这仍然可能比扫描桌子的速度更快!
(city,name,id)的索引将是您查询的最佳索引。它可以轻松找到所有想要的城市条目,并且不需要访问基础表来获取id和名称值。