我有这张表:
id bigint primary key,
catx_1 varchar(3),
catx_2 varchar(3),
catx_3 varchar(3),
caty_1 varchar(3),
caty_2 varchar(3)
假设 (catx_1, catx_2, catx_3) 和 (caty_1, caty_2) 是“原子”的,因此当通过 catx查找表时strong>,应该从catx_1然后catx_2和catx_3完成,caty也是如此。
更清楚地说,where 条件的变化可以是以下之一:
#single catx
where catx_1 = x1
where catx_1 = x1 and catx_2 = x2
where catx_1 = x1 and catx_2 = x2 and catx_3 = x3
#where catx_2 = x2 and catx_3 = x3 --> is impossible
#where catx_1 = x1 and catx_3 = x3 --> is impossible too
#single caty
where caty_1 = y1
where caty_1 = y1 and caty_2 = y2
#where caty_2 = y2 --> impossible
#mixed catx and caty
where catx_1 = x1 and catx_2 = x2 and catx_3 = x3 and caty_1 = y1 and caty_2 = y2
where catx_1 = x1 and catx_2 = x2 and caty_1 = y1 and caty_2 = y2
where catx_1 = x1 and caty_1 = y1 and caty_2 = y2
where catx_1 = x1 and caty_1 = y1
where catx_1 = x1 and catx_2 = x2 and catx_3 = x3 and caty_1 = y1
where catx_1 = x1 and catx_2 = x2 and caty_1 = y1
where caty_1 = y1 and caty_2 = y2
where caty_1 = y1
#and so on..
我的问题是,如何为上述条件创建最佳索引。我不认为为上述每个变体创建索引是正确的答案。 抱歉,如果我的解释不够好。
感谢您的回答。
最佳答案
这看起来确实像您有一个包含多个类别路径的表。有更好的方法来构建这样的东西,以便它......
- 可有效索引
- 可以支持任意数量的类别
- 可以支持任意长度的类别
首先,我们需要将类别的各个部分折叠到单个字段中。我们可以利用like 'foo%'
将使用索引( like '%foo%'
不会)。使用单个字段并使用分隔符存储类别,如 x1/
, x1/x2/
, x1/x2/x3/
.
create table sample (
id bigint primary key,
cat1 varchar(10),
cat2 varchar(10),
index(cat1, cat2)
);
现在您的搜索变得简单索引 like
s。
-- Matches x1/ x1/x2/ x1/x2/x3/
where catx_1 like 'x1/%';
-- Matches x1/x2/ and x1/x3/
where catx_1 like 'x1/x2/%';
-- Matches x1/x2/x3/
where catx_1 like 'x1/x2/x3/%;
<小时/>
每当你有类似 col1
的内容时, col2
, col3
这表明您需要一个一对多连接表来保存它们。一件事有很多类别。
create table things_categories (
thing_id bigint not null,
category varchar(255) not null,
foreign key(thing_id) references things(id)
on delete cascade,
index(category, thing_id)
);
insert into things_categories (thing_id, category) values
(1, "foo/bar/"),
(1, "up/"),
(1, "foo/"),
(2, "this/that/whatever"),
(3, "foo/"),
(3, "left/right/");
请注意,它现在是 category, thing_id
上的简单复合索引。 .
然后,当您想检查某个事物是否与多个类别匹配时,您可以执行内部 self join在 table 上将具有事物类别的所有组合的行组合在一起。
-- inner self join to select all pairings of a thing's categories
select *
from things_categories tc1
inner join things_categories tc2
on tc1.thing_id = tc2.thing_id
and tc1.category != tc2.category;
tc1.thing_id tc1.category tc2.thing_id tc2.category
1 foo/ 1 foo/bar/
1 foo/ 1 up/
3 foo/ 3 left/right/
1 foo/bar/ 1 up/
1 foo/bar/ 1 foo/
3 left/right/ 3 foo/
1 up/ 1 foo/bar/
1 up/ 1 foo/
然后您可以过滤t1.category
和t2.category
.
select distinct tc1.thing_id
from things_categories tc1
inner join things_categories tc2
on tc1.thing_id = tc2.thing_id
and tc1.category != tc2.category
where tc2.category like 'left/%'
and tc1.category like 'foo/%'
thing_id
3
如果您想做三个类别,请添加另一个自连接。
<小时/>最后,将其用作 CTE并与其连接以获取有关事物的信息。
with matching_things as (
select distinct tc1.thing_id as thing_id
from things_categories tc1
inner join things_categories tc2
on tc1.thing_id = tc2.thing_id
and tc1.category != tc2.category
where tc2.category like 'left/%'
and tc1.category like 'foo/%'
)
select t.*
from things t
inner join matching_things mt on mt.thing_id = t.id
id name
3 third
这可能看起来是一种奇怪的解决问题的方法,确实如此,但这就是在关系数据库中执行操作的方式:使用关系。
关于mysql - 为多个复合索引设计表架构和/或索引的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58620664/