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 索引中也包括 metric
和 timestamp
列?
不要 标准化 "continuous" 值,例如 DATETIME
、FLOAT
、INT
。 Do 保留主 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':
- 进入
a
找到 x=123 的行;获取这些行的 id(s)
。这可能包括许多尚未被 b.y
过滤的行。 a
需要 INDEX(x)
- 返回
main
table,查找具有这些 ID 的行。 main
需要 INDEX(a_id)
。同样,可能会拖拉比必要更多的行。
- 只有现在,您才能到达
b
(使用 b_id
)来检查 y=345
;扔掉你一直拖来拖去的不必要的行。 b
需要 INDEX(b_id)
请注意我对 "haul around" 的评论。盲目地使用 *
(在 SELECT *
中)会增加问题——在执行这些步骤时所有的柱子都被拖来拖去。
另一方面...如果 x
和 y
在 main
table 中,那么代码的工作方式如下:
WHERE main.x = 123
AND main.y = 345
只需要INDEX(x,y)
(顺序不限)。它可以快速准确地找到所需的行。
在ORDER BY a.x, b.y
的情况下,它不能在any table上使用any索引。因此查询 必须 创建一个 tmp table,对其进行排序,然后按所需顺序传送行。
但是如果x
和y
在同一个table,那么INDEX(x,y)
(按这个顺序)可能对 ORDER BY x,y
有用并避免 tmp table 和排序。
对于单个 table,优化器可能会使用 WHERE
的索引,或者它可能会使用 ORDER BY
的索引,具体取决于月相。在某些情况下,一个索引可以同时用于两者——这是最优的。
另一个注意事项:如果您还有 LIMIT 10
,...如果避免 sort
,则只需要查看 10 行,而不是 [=47 中的整个集合=].
我们有一个数据库 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 索引中也包括 metric
和 timestamp
列?
不要 标准化 "continuous" 值,例如 DATETIME
、FLOAT
、INT
。 Do 保留主 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':
- 进入
a
找到 x=123 的行;获取这些行的id(s)
。这可能包括许多尚未被b.y
过滤的行。a
需要INDEX(x)
- 返回
main
table,查找具有这些 ID 的行。main
需要INDEX(a_id)
。同样,可能会拖拉比必要更多的行。 - 只有现在,您才能到达
b
(使用b_id
)来检查y=345
;扔掉你一直拖来拖去的不必要的行。b
需要INDEX(b_id)
请注意我对 "haul around" 的评论。盲目地使用 *
(在 SELECT *
中)会增加问题——在执行这些步骤时所有的柱子都被拖来拖去。
另一方面...如果 x
和 y
在 main
table 中,那么代码的工作方式如下:
WHERE main.x = 123
AND main.y = 345
只需要INDEX(x,y)
(顺序不限)。它可以快速准确地找到所需的行。
在ORDER BY a.x, b.y
的情况下,它不能在any table上使用any索引。因此查询 必须 创建一个 tmp table,对其进行排序,然后按所需顺序传送行。
但是如果x
和y
在同一个table,那么INDEX(x,y)
(按这个顺序)可能对 ORDER BY x,y
有用并避免 tmp table 和排序。
对于单个 table,优化器可能会使用 WHERE
的索引,或者它可能会使用 ORDER BY
的索引,具体取决于月相。在某些情况下,一个索引可以同时用于两者——这是最优的。
另一个注意事项:如果您还有 LIMIT 10
,...如果避免 sort
,则只需要查看 10 行,而不是 [=47 中的整个集合=].