MySQL:为什么不在每一列上创建索引?为列建立索引的成本是多少?

Bin*_*ing 2 mysql php

知道我不应该在每一列上都有索引,但我不知道为什么。费用是多少?

我有一个包含大约 400 个表的系统,其中许多表都有日期时间或外键(实际上可能没有外键规则,因为它们不严格),并且缺乏索引。这可能会导致相对简单的查询(例如:具有时间条件和表主键的 3 个表中的 3 列)需要大量查询时间。

运行相关查询的时间花费了 2 分钟多,但是一旦我添加了时间戳和外键索引,时间就下降到 200 毫秒以下,增加了 6000%。我很想在我有指标的每一列上添加索引,但我知道(从其他人告诉我)过多的索引是不好的。但我在任何地方都找不到原因!

所以我的问题的根本是:什么是“太多”索引,为什么?

J.D*_*.D. 9

索引实际上存储数据的副本,按该索引覆盖的字段排序(并自动包含聚集索引键),通常采用称为 B 树的数据结构。在每个表的每个字段上创建索引实际上会使数据库中的数据量增加三倍(大约)。

除了额外的空间要求之外,将数据写入表(特别是磁盘)也需要时间。对于表上的每个索引,每当将记录插入表中时,都必须进行额外的写入操作才能持久保存数据。索引过多可能会影响数据库的整体写入速度,并导致不必要的争用和表锁定时间过长。

此外,当索引覆盖(定义)属于查询谓词( JOINWHERE或子句)的字段时,索引也是最佳的。HAVING例如,如果您有以下谓词,WHERE Field1 = 91 AND Field2 = 13但您在 on 上定义了索引(Field3, Field1, Field2),那么您的索引不会覆盖您的WHERE子句,并且如果用于为该查询提供数据,则可能不会使用或不会发挥作用,因为它无法当该索引首次按不在谓词中的字段排序时,搜索查询中使用的字段。

您在索引定义中指定字段的顺序定义了它涵盖的谓词,因为它是字段在 B 树中排序的顺序。因此,仔细设计索引以尽可能覆盖您的查询非常重要。通常,这不是通过为每个单独的字段创建索引来实现的,而且通常字段太多,无法为谓词中可能使用的每种可能的组合合理地创建索引。

或者,最好确定最慢、最重和最常用的查询和谓词,然后测试索引是否是改进它们的解决方案。没有适合每个人的固定数量的索引,但我喜欢作为起点的一般经验法则是我所说的 5 x 5 规则。5 x 5 规则是尝试为每个表创建不超过 5 个索引,并且尝试每个索引定义包含不超过 5 个列。当然,这是一个软规则,在某些情况下跨越这些阈值是可以的。