复合索引最左边的列中的通配符是否意味着索引中剩余的列不是';是否在索引查找(MySQL)中使用t?

复合索引最左边的列中的通配符是否意味着索引中剩余的列不是';是否在索引查找(MySQL)中使用t?,mysql,wildcard,sql-like,query-performance,composite-index,Mysql,Wildcard,Sql Like,Query Performance,Composite Index,假设您有一个主要的复合索引姓、名。然后您执行了搜索,其中名字像'joh%'和姓氏像'smi%' last_name条件中使用的通配符是否意味着first_name条件将不会用于进一步帮助MySQL查找索引?换句话说,通过在last_name条件上添加通配符,MySQL将只执行部分索引查找(并忽略last_name右侧列中给定的条件) 进一步澄清我的问题 示例1:主键是姓、名 示例2:主键是姓氏 使用WHERE子句:如果名字像'joh%'和姓氏像'smi%',示例1会比示例2快吗 更新 下面是一个

假设您有一个主要的复合索引
姓、名
。然后您执行了
搜索,其中名字像'joh%'和姓氏像'smi%'

last_name条件中使用的通配符是否意味着first_name条件将不会用于进一步帮助MySQL查找索引?换句话说,通过在last_name条件上添加通配符,MySQL将只执行部分索引查找(并忽略last_name右侧列中给定的条件)

进一步澄清我的问题

示例1:主键是
姓、名

示例2:主键是
姓氏

使用WHERE子句:
如果名字像'joh%'和姓氏像'smi%'
,示例1会比示例2快吗

更新

下面是一个sqlfiddle:


这是你的问题。复数的通过重新措辞(用“换句话说”),它们只是不同的问题。这样做并不一定会让响应者更容易。恰恰相反

Q1:[标题问题]复合索引最左边的列中的通配符是否意味着索引中的其余列不用于索引查找(MySQL)

A1:不,这并不意味着


问题2:last_name条件中使用的通配符是否意味着first_name条件将不会用于进一步帮助MySQL查找索引

答2:不,不是这个意思。另外,这个问题的结尾是模棱两可的。它已经知道使用什么索引可能是对这种模糊性的一个分支答案


问题3:换句话说,通过在姓氏条件上添加通配符,MySQL将只执行部分索引查找(并忽略姓氏右侧列中给定的条件)

A3:不是。最右边的列由索引提供,类似于覆盖索引策略,受益于数据页查找的缓慢


问题4:…示例1会比示例2快吗

A4:是的。它是关于这些列的覆盖索引。参见覆盖索引

作为第四季度的旁白。如果是PK或非PK,则不相关。可能有十几个原因可以解释为什么PK对您的应用程序来说是可怕的


原始答复如下:

只有一个复合键在
(姓、名)
还有你提到的一个问题

WHERE first_name LIKE 'joh%'
。。。它根本不会使用索引。它将进行表格扫描。由于没有

  • first\u name
  • 最左边有
    名字的复合键
我们来了,开始扫描表格。

请参阅手册页了解更多信息。并关注it最左边的
概念。事实上,请转到该页面,并在单词
左侧搜索

请参阅mysql中有关该工具的手册页面。还有文章


编辑 自从我一两个小时前来到这里以来,这个问题已经有了一些修改。我将留给你以下内容。通过explain运行实际查询,并使用上面的explain…
链接或其他参考通过
进行解密

drop table myNames;
create table myNames
(   id int auto_increment primary key,
    lastname varchar(100) not null,
    firstname varchar(100) not null,
    col4 int not null,
    key(lastname,firstname)
);
truncate table myNames;
insert myNames (lastName,firstName,col4) values
('Smith','John',1),('Smithers','JohnSomeone',1),('Smith3','John4324',1),('Smi','Jonathan',1),('Smith123x$FA','Joh',1),('Smi3jfif','jkdid',1),('r3','fe2',1);

insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;
insert myNames (lastName,firstName,col4) select lastname,firstname,col4 from mynames;

select count(*) from myNames; 
-- 458k rows

select count(*)
from myNames
where lastname like 'smi%';
-- 393216 rows

select count(*)
from myNames
where lastname like 'smi%' and firstname like 'joh%';
-- 262144 rows
Explain
呈现伏都教数字。巫毒?是的,因为一个查询可能会运行一个小时,所以您要求
explain
给您一个模糊计数,而不是运行它,并在2秒或更短的时间内给您答案。不要认为这些是实际运行时的标准计数,而不是<代码>解释< /代码> .<
explain 
select count(*) 
from myNames 
where lastname like 'smi%';
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref  | rows   | Extra                    |
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | myNames | range | lastname      | lastname | 302     | NULL | 233627 | Using where; Using index |
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+

explain 
select count(*) 
from myNames 
where lastname like 'smi%' and firstname like 'joh%' and col4=1;
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref  | rows   | Extra                    |
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | myNames | range | lastname      | lastname | 604     | NULL | 233627 | Using where; Using index |
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+


-- the below chunk is interest. Look at the Extra column

explain 
select count(*) 
from myNames 
where lastname like 'smi%' and firstname like 'joh%' and col4=1;
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | myNames | ALL  | lastname      | NULL | NULL    | NULL | 457932 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

explain 
select count(*) 
from myNames 
where firstname like 'joh%';
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref  | rows   | Extra                    |
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | myNames | index | NULL          | lastname | 604     | NULL | 453601 | Using where; Using index |
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+


analyze table myNames;
+----------------------+---------+----------+----------+
| Table                | Op      | Msg_type | Msg_text |
+----------------------+---------+----------+----------+
| so_gibberish.mynames | analyze | status   | OK       |
+----------------------+---------+----------+----------+

select count(*) 
from myNames where left(lastname,3)='smi';
-- 393216 -- the REAL #
select count(*) 
from myNames where left(lastname,3)='smi' and left(firstname,3)='joh';
-- 262144 -- the REAL #

explain 
select lastname,firstname 
from myNames  
where lastname like 'smi%' and firstname like 'joh%';
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref  | rows   | Extra                    |
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+
|  1 | SIMPLE      | myNames | range | lastname      | lastname | 604     | NULL | 226800 | Using where; Using index |
+----+-------------+---------+-------+---------------+----------+---------+------+--------+--------------------------+

实际上,@Drew所说的一切都假设该指数“覆盖”

是一个“覆盖”指数

SELECT COUNT(*)   FROM t WHERE first_name LIKE 'joh%' AND last_name LIKE 'smi%'.
SELECT last_name  FROM t WHERE first_name LIKE 'joh%' AND last_name LIKE 'smi%'.
SELECT id         FROM t WHERE first_name LIKE 'joh%' AND last_name LIKE 'smi%'. -- if the table is InnoDB and `id` is the `PRIMARY KEY`.
但它并不是在“掩盖”自己

这是因为
foo
不包括在索引中。对于非覆盖情况,答案完全不同:

Q1:[标题问题]复合索引最左边的列中的通配符是否意味着索引中的其余列不用于索引查找(MySQL)

A1:是的,它的意思是

问题2:last_name条件中使用的通配符是否意味着first_name条件将不会用于进一步帮助MySQL查找索引

我迷失在模糊中。优化器将查看所有索引,而不仅仅是有问题的索引。它将挑选“最好的”

问题3:换句话说,通过在姓氏条件上添加通配符,MySQL将只执行部分索引查找(并忽略姓氏右侧列中给定的条件)

A3:是的。这似乎是第一季度的重复

问题4:…示例1会比示例2快吗


A4:不会。在极端情况下,
索引(姓)
将比
索引(姓、名)
慢。两个示例都只使用索引的第一部分(姓氏)。然而,盘面上的综合指数更大。对于一个巨大的表,这可能会导致缓存的表的百分比降低,因此磁盘命中率会增加,因此速度会变慢。

我已经确认Rick James上面的回答是正确的。然而,Drew和Rick James指出,根据我的选择,我可以使用覆盖索引

关于使用通配符时是否使用了所有关键部分,MySQL文档说:

对于BTREE索引,对于组合条件,间隔可能是可用的 使用和,其中每个条件将一个关键部分与一个常量进行比较 使用=,值为空,>,=,=,=从 第二个比较,但不考虑其他关键部分,不考虑 将第三个比较用于区间构造

关键部分1='foo'和关键部分2>=10和关键部分3>10

单一间隔为:

('foo',10,-inf)<(第1部分,第2部分,第3部分)<('foo',+inf,+inf)

创建的间隔可能包含更多行
INDEX(last_name, first_name)
SELECT COUNT(*)   FROM t WHERE first_name LIKE 'joh%' AND last_name LIKE 'smi%'.
SELECT last_name  FROM t WHERE first_name LIKE 'joh%' AND last_name LIKE 'smi%'.
SELECT id         FROM t WHERE first_name LIKE 'joh%' AND last_name LIKE 'smi%'. -- if the table is InnoDB and `id` is the `PRIMARY KEY`.
SELECT foo ...
SELECT foo, last_name ...
etc.