gpt4 book ai didi

MySQL 二叉树索引顺序

转载 作者:行者123 更新时间:2023-11-29 09:11:57 25 4
gpt4 key购买 nike

我有一个这样的查询:

SELECT * FROM mytable WHERE
((num=8198747 AND class='A') OR
(num=1646463 AND class='B') OR
(num=4099442 AND class='C') OR
(num=1176312 AND class='A') OR
(num=2146847 AND class='B') OR
(num=7000296 AND class='F') OR
--...about 400 more clauses like this
)

SHOW INDEXES FROM mytable;
+---------+------------+----------+--------------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name |
+---------+------------+----------+--------------+---------------+
| mytable | 0 | PRIMARY | 1 | id |
| mytable | 1 | nc_idx | 1 | num |
| mytable | 1 | nc_idx | 2 | class |
+---------+------------+----------+--------------+---------------+
3 rows in set (0.00 sec)

我的理解是,对于查询中大约 400 个子句中的每个子句,它将对 num=XXXXXXXXX 进行单独的 BTREE 查找。将查询更改为以下内容是否有任何值(value):

SELECT * FROM mytable WHERE
((class='A' AND num IN (8198747, 1176312, ...)) OR
(class='B' AND num IN (1247910, 1248192, ...)) OR
(class='F' AND num IN (7244626, 9084903, ...)) OR
--...for each class in the query
)

classnum 上添加新索引 cn_idx 后,按这个顺序?我认为它不会快得多,因为 class 只是一个字符,因此 BTREE 查找的数量将是相同的。但是,每个子树都会更短。想法?

最佳答案

简而言之

  • 只需坚持OR
  • num 上的索引是唯一有助于此查询的索引
  • (num,class) 上的复合索引的影响可以忽略不计,因为 num 已经具有很强的选择性
<小时/>

另外两种写法,使用 UNION ALL

SELECT * FROM mytable
WHERE (num=8198747 AND class='A')
UNION ALL
SELECT * FROM mytable
WHERE (num=1646463 AND class='B')
UNION ALL
SELECT * FROM mytable
WHERE (num=4099442 AND class='C')
UNION ALL
... etc ...

如果您没有太多的 num/class 对,这可能会很有效,因为每个对都会单独执行索引查找。 (num/class 上的复合索引比 num 和 class 索引单字段索引效果更好。class/num 的选择性较差)

第二种方法使用 JOIN 机制,通过 num/class 对创建虚拟表:

SELECT t.*
FROM mytable t
JOIN (
select 8198747 as num, 'A' as class union all
select 1646463, 'B' union all
select 4099442, 'C' union all
... etc ...
) v on v.num=t.num and v.class=t.class

性能比较

创建一个表

create table mytable (
id int auto_increment primary key,
num int,
class char(1),
other varchar(10),
date timestamp default current_timestamp) ENGINE InnoDB;

填充 100 万条记录
(注:数据属性 - 选择性:num ~ 1,class ~ 1/26)

insert into mytable(num, class, other)
select rand()*100000000, char(rand()*26+65), concat('',rand()*10000000)
from
(select 1 a union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7
union all select 8 union all select 9 union all select 0) a,
(select 1 a union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7
union all select 8 union all select 9 union all select 0) b,
(select 1 a union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7
union all select 8 union all select 9 union all select 0) c,
(select 1 a union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7
union all select 8 union all select 9 union all select 0) d,
(select 1 a union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7
union all select 8 union all select 9 union all select 0) e,
(select 1 a union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7
union all select 8 union all select 9 union all select 0) f

创建索引

create index nc_num on mytable(num);
create index nc_class on mytable(class);

使用 OR 选择

select * from mytable
WHERE
(num=38142659 and class='T') OR
(num=42476845 and class='E') OR
(num=45205882 and class='B') OR
(num=84861596 and class='K') OR
..... 100 in total

Show profiles 的输出:(运行 set profiling=1; 一次。然后运行查询。运行 show profile 以查看最后的计时)

Duration: 0.00003025

解释扩展(在查询之前添加解释扩展)

"id";"select_type";"table";"type";"possible_keys";"key";"key_len";"ref";"rows";"Extra"
"1";"SIMPLE";"mytable";"range";"nc_num,nc_class";"nc_num";"5";NULL;"125";"Using where"

在 num/class 之间使用 UNION ALL 进行选择

SELECT * FROM mytable WHERE (num=38142659 AND class='T') UNION ALL
SELECT * FROM mytable WHERE (num=42476845 AND class='E') UNION ALL
SELECT * FROM mytable WHERE (num=45205882 AND class='B') UNION ALL
SELECT * FROM mytable WHERE (num=84861596 AND class='K') UNION ALL
.... 100 in total

显示个人资料

Duration: 0.00069525

解释扩展

"id";"select_type";"table";"type";"possible_keys";"key";"key_len";"ref";"rows";"Extra"
"1";"PRIMARY";"mytable";"ref";"nc_num,nc_class";"nc_num";"5";"const";"1";"Using where"
"2";"UNION";"mytable";"ref";"nc_num,nc_class";"nc_num";"5";"const";"1";"Using where"
"3";"UNION";"mytable";"ref";"nc_num,nc_class";"nc_num";"5";"const";"1";"Using where"
"4";"UNION";"mytable";"ref";"nc_num,nc_class";"nc_num";"5";"const";"1";"Using where"
... etc

选择使用Union All建立虚拟表

SELECT t.*
FROM mytable t
JOIN (
select 41805446 num, 'X' collate utf8_general_ci class union all
select 84867135, 'P' union all
select 52747446, 'R' union all
.... etc...
) v on v.num=t.num and v.class=t.class

显示个人资料

Duration: 0.00026100

解释扩展

"id";"select_type";"table";"type";"possible_keys";"key";"key_len";"ref";"rows";"Extra"
"1";"PRIMARY";"<derived2>";"ALL";NULL;NULL;NULL;NULL;"100";""
"1";"PRIMARY";"t";"ref";"nc_num";"nc_num";"5";"v.num";"1";"Using where"
"2";"DERIVED";NULL;NULL;NULL;NULL;NULL;NULL;NULL;"No tables used"
"3";"UNION";NULL;NULL;NULL;NULL;NULL;NULL;NULL;"No tables used"
"4";"UNION";NULL;NULL;NULL;NULL;NULL;NULL;NULL;"No tables used"
....
"101";"UNION";NULL;NULL;NULL;NULL;NULL;NULL;NULL;"No tables used"
NULL;"UNION RESULT";"<union2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,...>";"ALL";NULL;NULL;NULL;NULL;NULL;""

使用 IN 选择

SELECT * FROM mytable WHERE
(class='A' and num in (28538065
)) or (class='B' and num in (70851926
,90457823
,94804149
)) or (class='C' and num in (74179050
,43280101
,24562525
,56859448
,38226813
,33532373
,93501613
,28634136
,8204338
,15636810
)) or (class='D' and num in (26672499
.... etc

显示个人资料

Duration: 0.00003125

解释扩展

"id";"select_type";"table";"type";"possible_keys";"key";"key_len";"ref";"rows";"Extra"
"1";"SIMPLE";"mytable";"range";"nc_num,nc_class";"nc_num";"5";NULL;"136";"Using where"

关于MySQL 二叉树索引顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5330295/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com