mysql - 为多个复合索引设计表架构和/或索引的最佳实践

标签 mysql indexing

我有这张表:

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,应该从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.categoryt2.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

dbfiddle

这可能看起来是一种奇怪的解决问题的方法,确实如此,但这就是在关系数据库中执行操作的方式:使用关系。

关于mysql - 为多个复合索引设计表架构和/或索引的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58620664/

相关文章:

excel - MATCH 函数不适用于单元格引用

mysql - 索引该查询

android - 如何在 View 上执行 onLongClick 后从 ViewGroup (FrameLayout) 获取特定(自定义) View 的索引

mysql - 对 SQL 数据库进行特定更新

mysql - 无法正确加入表格。查询花费的无限时间

javascript - PHP 查询数据库

mysql - 查询中有什么问题

php - 如何存储和检索特定日期检索+摘要检索的大量数据?

sql-server - 由于计划不当或索引碎片化,MS SQL 查询速度变慢

indexing - Apache Cassandra 。二级索引的优缺点