查询以显示 mysql 数据库中 B-Tree 索引的限制

Posted

技术标签:

【中文标题】查询以显示 mysql 数据库中 B-Tree 索引的限制【英文标题】:Query to show the limitations of B-Tree Index in mysql database 【发布时间】:2021-04-05 02:43:38 【问题描述】:

我想展示 mysql 中某些索引类型的一些限制。我已经读过,在包含布尔数据类型的列上使用 B-Tree 索引将是无效的,因为对于 True 或 False 结果的任何具有此索引类型的搜索查询都必须执行全表扫描。如何在 sql 查询中显示这一点?我尝试了以下查询,但无法证明上述声明是正确的,问题是如果我将查询中的性别更改为“F”,使用我创建的索引没有任何优势。请问有人可以向我展示一个可以证明 B-Tree 索引在布尔列上无效的查询吗?我正在使用流行的员工数据库。请注意(emp_no 列包含唯一值,但我已通过 WHERE 子句添加了性别列)。感谢您的帮助。

use employees;

CREATE INDEX indx_emp on employees(emp_no);

SELECT 
    *
FROM
    employees USE INDEX (indx_emp)
WHERE
    emp_no BETWEEN 10980 AND 100000
        AND gender = 'M'
ORDER BY birth_date;  

【问题讨论】:

请提供SHOW CREATE TABLE。并说出gender 的百分比是“F”。 此“复合”索引将是该查询的最佳索引:INDEX(gender, emp_no) 对于它的价值,数百年的程序员已经投入到优化 MySQL 中的查询计划功能(决定使用什么索引的东西)。这些都是高技能的程序员。您正在寻求一种方法来证明他们错过了一个特定的用例——一个常见的用例。这是一个很大的问题,因为 (a) 他们可能并没有完全错过它,并且 (b) 数据库服务器的每个版本都会变得更好。除非您阅读其源代码,否则很难证明对查询计划器这样复杂的事物的否定。 【参考方案1】:

在布尔列上使用索引与在任何其他数据类型的列上使用索引一样有效。

如果您听到有人声称布尔值的索引无效,他们会假设真值和假值分别出现在接近 50% 的行上。

事实上,如果你有一列是 90% 正确和 10% 错误,那么在索引中搜索错误的行将从索引中受益。但是,如果您在索引中搜索为 true 的行,则读取索引是不必要的开销。最好只进行表扫描。

这适用于任何其他数据类型。例如,如果您搜索与表中超过 20% 的行匹配的某个整数值(或值范围),则优化器可能会跳过索引而只进行表扫描。读取索引、取消引用指向行的指针然后读取行所花费的额外工作被认为比仅扫描表中的所有行并丢弃与您的条件不匹配的行更昂贵。

如果您搜索一个只有两个不同值的整数列,并且每个值都在表中大约 50% 的行中找到,这相当于搜索布尔值,其中 true 和 false 出现在大约 50% 的行中表,分别。在任何一种情况下,索引都不是很有选择性,因此优化器可能会跳过它。 varchar 或 datetime 或任何其他索引列类型也是如此。

我没有按照您的要求提供特定的查询,因为您显示的查询已经可以证明这一点。是否使用索引取决于数据以及您在该索引中搜索的值的选择性。

您应该使用EXPLAIN 分析查询,并比较优化器的选择以及它估计它将读取多少rows


20% 的数字不是官方阈值。它没有记录,这只是我观察到的。它可能会根据您搜索的数据类型而有所不同,或者在软件的某些其他版本中实现可能会发生变化。

【讨论】:

感谢您的回复,我明白您的意思,这很清楚,但请您分享任何可以显示此流行员工数据库上任何索引类型的任何限制的查询?感谢您的宝贵时间。 @Tunde - 我们需要知道你的表格每一列的数据分布情况。 @RickJames 我正在使用的数据库可以在这里找到 - dev.mysql.com/doc/employee/en/sakila-structure.html 结构就在那里,它有 300,000 条记录。非常感谢。 @Tunde 您正在寻找能证明您的主张是真实的查询,但既然不是,没有人可以给您。正如比尔试图向您解释的那样,如果索引用于特定查询,则取决于您的数据分布。尝试例如explain select * from customer where last_name >= 'A' and last_name <= 'M'explain select * from customer where last_name >= 'A' and last_name <= 'B' 在 sakila 上。一个使用索引,一个不使用,这取决于有多少行适合您的搜索条件。这同样适用于布尔索引,只需查找(或添加)不是 50/50 的列。 @O.Jones 你说“当然”就好像任何人都知道索引是这样工作的! :-) 事实上并不是每个 SQL 实现都支持覆盖索引。

以上是关于查询以显示 mysql 数据库中 B-Tree 索引的限制的主要内容,如果未能解决你的问题,请参考以下文章

数据库索引(BTree索引和Hash索引)

MySQL索引

MySQL索引

MySQL---索引

图解MySQL索引--B-Tree(B+Tree)

MySQL索引