假设有一个表,它有6个列组成一个唯一的索引。如果一个查询只连接了其中的3列,那么在这个查询上会有任何索引帮助吗?仅仅在这3列上创建一个新的非唯一索引会更有帮助吗?谢谢
qni6mghb1#
简短的回答是肯定的,你的查询在六个索引列中的三个上有 predicate 可以从索引中受益。但是它能受益多少取决于索引中列的顺序,以及你需要的三个列在列表中的位置。从索引的列列表的左侧开始,查询将查找(执行二进制搜索)逐步地对 predicate 上有相等运算符的每个索引列进行搜索,直到它到达一个没有相等 predicate 的索引列。在这一点上,您可能需要的右侧的任何列都必须通过索引叶节点的链表进行扫描,这意味着不再有二进制查找(因此更慢)。这对你的影响有多大取决于差距右边的那些附加列有多重要。如果你已经完成了大部分的行过滤,那么也许你不在乎。但是如果在差距右边有一个非常有选择性的列,那就有麻烦了。你的查询在 * 前导 * 上有一个相等 predicate 是特别重要的索引的最左列,否则Oracle将根本不使用索引,或者将尝试低效的跳过扫描。这有多糟糕取决于它跳过的列的非重复值的数量(越多,越糟糕)。所以,想象一个employee表,它有一个连接索引:第一个月假设这是你的查询:SELECT * FROM employee WHERE last_name = 'Smith' and State = 'CA'个这将对last_name进行二进制搜索,但随后必须扫描该姓氏中的所有叶节点,以测试state过滤器。它不能继续使用二进制查找方法来查找状态,因为未使用的first_name在索引中位于它们之间。SELECT * FROM employee WHERE last_name = 'Smith' and first_name = 'John' AND gender = 'M'个这将在last_name和first_name上进行搜索,然后扫描所有的叶块,这些值应用gender的过滤器。但这可能是好的,因为当你分离姓氏和名字时,性别不会明显减少你的行数,特别是如果名字往往已经与性别相关。SELECT * FROM employee WHERE first_name = 'John'此查询将根本不使用索引,因为您没有将 predicate 应用于前导/最左边的列(last_name),但它可以进行跳过扫描,这将需要在每个last_name值内对first_name进行单独的二进制查找。如果您有100个不同的John,则是100次查找操作而不是1次。不是很好。但是,像这样的查询多久运行一次?它需要多长时间?如果它仍然快或足够快,那么我们可能不关心它运行的频率。想象一下这个:SELECT * FROM employee WHERE employee_id = 1234这个索引没有任何帮助。虽然employee_id被索引了,但它不是前导列,甚至不靠近左边缘,所以跳过扫描也没有帮助。像employee_id这样非常有选择性的列需要被移动到索引的左边缘,或者给它自己的索引,以方便需要它的查询。最后,假设 predicate 位于索引的前三列:SELECT * FROM employee WHERE last_name = 'Smith' and first_name = 'John' AND state = 'CA'与只包含这三个列的新索引相比,即使在右边有不使用的其他列,这也将与现有索引一样好地执行。好吧,几乎一样好。如果 predicate 匹配许多(即成千上万)行,你最终不得不扫描叶块来读取它们,每个块的索引条目越多,你需要扫描的块就越少,所以索引中不需要的列越少,所需的I/O就越少,因为每个块可以容纳更多的条目。但通常这是最不重要的,特别是在使用缓存的情况下。与为选择性 predicate 使用前导列的重要性相比,它相形见绌。总之,什么最适合你取决于你的数据,它的基数,以及对它的查询。
SELECT * FROM employee WHERE last_name = 'Smith' and State = 'CA'
last_name
state
first_name
SELECT * FROM employee WHERE last_name = 'Smith' and first_name = 'John' AND gender = 'M'
gender
SELECT * FROM employee WHERE first_name = 'John'
SELECT * FROM employee WHERE employee_id = 1234
employee_id
SELECT * FROM employee WHERE last_name = 'Smith' and first_name = 'John' AND state = 'CA'
1条答案
按热度按时间qni6mghb1#
简短的回答是肯定的,你的查询在六个索引列中的三个上有 predicate 可以从索引中受益。但是它能受益多少取决于索引中列的顺序,以及你需要的三个列在列表中的位置。
从索引的列列表的左侧开始,查询将查找(执行二进制搜索)逐步地对 predicate 上有相等运算符的每个索引列进行搜索,直到它到达一个没有相等 predicate 的索引列。在这一点上,您可能需要的右侧的任何列都必须通过索引叶节点的链表进行扫描,这意味着不再有二进制查找(因此更慢)。
这对你的影响有多大取决于差距右边的那些附加列有多重要。如果你已经完成了大部分的行过滤,那么也许你不在乎。但是如果在差距右边有一个非常有选择性的列,那就有麻烦了。你的查询在 * 前导 * 上有一个相等 predicate 是特别重要的索引的最左列,否则Oracle将根本不使用索引,或者将尝试低效的跳过扫描。这有多糟糕取决于它跳过的列的非重复值的数量(越多,越糟糕)。
所以,想象一个employee表,它有一个连接索引:
第一个月
假设这是你的查询:
SELECT * FROM employee WHERE last_name = 'Smith' and State = 'CA'
个这将对
last_name
进行二进制搜索,但随后必须扫描该姓氏中的所有叶节点,以测试state
过滤器。它不能继续使用二进制查找方法来查找状态,因为未使用的first_name
在索引中位于它们之间。SELECT * FROM employee WHERE last_name = 'Smith' and first_name = 'John' AND gender = 'M'
个这将在
last_name
和first_name
上进行搜索,然后扫描所有的叶块,这些值应用gender
的过滤器。但这可能是好的,因为当你分离姓氏和名字时,性别不会明显减少你的行数,特别是如果名字往往已经与性别相关。SELECT * FROM employee WHERE first_name = 'John'
此查询将根本不使用索引,因为您没有将 predicate 应用于前导/最左边的列(
last_name
),但它可以进行跳过扫描,这将需要在每个last_name
值内对first_name
进行单独的二进制查找。如果您有100个不同的John,则是100次查找操作而不是1次。不是很好。但是,像这样的查询多久运行一次?它需要多长时间?如果它仍然快或足够快,那么我们可能不关心它运行的频率。想象一下这个:
SELECT * FROM employee WHERE employee_id = 1234
这个索引没有任何帮助。虽然
employee_id
被索引了,但它不是前导列,甚至不靠近左边缘,所以跳过扫描也没有帮助。像employee_id
这样非常有选择性的列需要被移动到索引的左边缘,或者给它自己的索引,以方便需要它的查询。最后,假设 predicate 位于索引的前三列:
SELECT * FROM employee WHERE last_name = 'Smith' and first_name = 'John' AND state = 'CA'
与只包含这三个列的新索引相比,即使在右边有不使用的其他列,这也将与现有索引一样好地执行。好吧,几乎一样好。如果 predicate 匹配许多(即成千上万)行,你最终不得不扫描叶块来读取它们,每个块的索引条目越多,你需要扫描的块就越少,所以索引中不需要的列越少,所需的I/O就越少,因为每个块可以容纳更多的条目。但通常这是最不重要的,特别是在使用缓存的情况下。与为选择性 predicate 使用前导列的重要性相比,它相形见绌。
总之,什么最适合你取决于你的数据,它的基数,以及对它的查询。