MySql 多个共享列的索引策略

MySql Indexing Strategy With Multiple Shared Columns

我们有一个数据库 table,它存储访问者的浏览器数据,按多种不同的子类型细分。为简单起见,让我们使用下面的 table 架构。查询基本上是在任何单个 id 列、指标列、时间戳列(存储为自纪元以来的秒数)以及设备、浏览器或 os 列之一。

我们将对星形模式与雪花模式进行性能测试(其中所有 ID 都放在一个列中,但随后添加了一个额外的列 id_type 以确定它是哪种类型的标识符)这个 table,但只要星型模式(现在是这样)在雪花性能的 80% 以内,我们就会保留它,因为它会使我们的加载过程更容易。然而,在我这样做之前,我想确保索引在星型模式上得到优化。

create table browser_data (
id_1 int,
id_2 int,
id_3 int,
id_4 int,
metric varchar(20),
browser varchar(20),
device varchar(20),
os varchar(20),
timestamp bigint
)

只在 id 列上创建单独的索引会更好,还是在 ose 索引中也包括 metrictimestamp 列?

不要 标准化 "continuous" 值,例如 DATETIMEFLOATINTDo 保留主 table 中的值。

当您将值移动到其他 table(s) 时,尤其是 "snowflake",它会根据介于稍慢和 之间的某个值进行查询很多 较慢。当您需要过滤不在主要 table 中的多个指标时,尤其会发生这种情况。由于 "snowflake" 或 "over-normalization":

WHERE a.x = 123 AND b.y = 345

ORDER BY a.x, b.y

至于要创建什么索引——这完全取决于您需要执行的查询。所以,我强烈建议你根据你的暂定 CREATE TABLEs.

勾勒出可能的 SELECTs

INT 是 4 个字节。 TIMESTAMP 是 5,FLOAT 是 4,等等。也就是说,规范化这些东西在 space.

上也是低效的

更多

执行 JOINs 时,优化器几乎总是从一个 table 开始,然后移动到另一个 table,等等。(参见 "Nested Loop Join"。)

例如(建立在上面的 'code' 上),当 2 列被归一化时,你正在测试这些值,你手头没有两个 ids,你只有两个值。这使得查询执行效率非常低。对于

SELECT ...
    FROM main
    JOIN a  USING(a_id)
    JOIN b  USING(b_id)
    WHERE a.x = 123 AND b.y = 345

以下很可能是'execution plan':

  1. 进入 a 找到 x=123 的行;获取这些行的 id(s) 。这可能包括许多尚未被 b.y 过滤的行。 a 需要 INDEX(x)
  2. 返回 main table,查找具有这些 ID 的行。 main 需要 INDEX(a_id)。同样,可能会拖拉比必要更多的行。
  3. 只有现在,您才能到达 b(使用 b_id)来检查 y=345;扔掉你一直拖来拖去的不必要的行。 b 需要 INDEX(b_id)

请注意我对 "haul around" 的评论。盲目地使用 *(在 SELECT * 中)会增加问题——在执行这些步骤时所有的柱子都被拖来拖去。

另一方面...如果 xymain table 中,那么代码的工作方式如下:

WHERE main.x = 123
  AND main.y = 345

只需要INDEX(x,y)(顺序不限)。它可以快速准确地找到所需的行。

ORDER BY a.x, b.y的情况下,它不能在any table上使用any索引。因此查询 必须 创建一个 tmp table,对其进行排序,然后按所需顺序传送行。

但是如果xy在同一个table,那么INDEX(x,y)(按这个顺序)可能ORDER BY x,y 有用并避免 tmp table 和排序。

对于单个 table,优化器可能会使用 WHERE 的索引,或者它可能会使用 ORDER BY 的索引,具体取决于月相。在某些情况下,一个索引可以同时用于两者——这是最优的。

另一个注意事项:如果您还有 LIMIT 10,...如果避免 sort,则只需要查看 10 行,而不是 [=47 中的整个集合=].