rap*_*2-h 29 mysql indexing optimization laravel eloquent
如果我在laravel 4.2(数据库是mysql)中使用软删除,那么每个雄辩的构建查询都有WHERE deleted_at IS NULL.没有索引deleted_at.
那么,Laravel的"soft_delete"是否需要MySQL的索引?
N.B*_*.B. 51
该列deleted_at不是一个好的索引候选者.与评论相比,我会尝试更好地解释:索引仅在其基数相对较高时才有用.基数是描述数据集中索引唯一性的数字.这意味着它的总记录数除以总的唯一记录.
例如,主键的基数为1.每个记录包含主键的唯一值.1也是最高的数字.您可以将其视为"100%".
但是,像deleted_at这样的列没有这样的值.Laravel对deleted_at的作用是检查它是否为空.这意味着它有两个可能的值.包含两个值的列具有极低的基数,随着记录数量的增加而减少.
您可以索引此类列,但它不会有任何帮助.会发生什么事情会减慢速度并占用空间.
TL; DR:不,您不必索引该列,索引对性能没有任何有益影响.
简短的回答:也许吧。
长答案:
如果有很少的不同值deleted_at,MySQL将不会使用INDEX(deleted_at)。
如果 中存在不同的非空日期deleted_at,MySQL 将使用INDEX(deleted_at).
大多数讨论(到目前为止)都未能考虑到这个单列索引的基数。
注意:这与 2 值标志(例如 )不同is_deleted。 对于这样的单列索引是没有用的。
更多讨论(从MySQL的角度)
https://laravel.com/docs/5.2/eloquent#soft-deleting说
现在,当您在模型上调用删除方法时,deleted_at 列将设置为当前日期和时间。并且,当查询使用软删除的模型时,软删除的模型将自动从所有查询结果中排除。
由此,我假设这发生在表定义中:
deleted_at DATETIME NULL -- (or TIMESTAMP NULL)
Run Code Online (Sandbox Code Playgroud)
并且该值被初始化(显式或隐式)为NULL。
情况 1:大量新行,尚未“删除”:所有值deleted_at都是NULL. 在这种情况下,优化器将INDEX(deleted_at)因为没有帮助而回避。事实上,使用索引会带来伤害,因为遍历整个索引和数据会花费更多。忽略索引并简单地假设所有行都是 的候选行会更便宜SELECTed。
情况 2:(多行中的)几行已被删除:现在deleted_at有多个值。虽然 Laravel 只关心IS NULLvs IS NOT NULL,但 MySQL 将其视为多值列。但是,由于测试是IS NULL且大多数行仍然是NULL,优化器的反应与情况 1 相同。
情况 3:软删除的行比仍然活动的行多得多:现在索引突然变得有用,因为只有表的一小部分IS NULL。
案例 2 和案例 3 之间没有确切的界限。20% 是一个方便的经验法则。
现在,从执行的角度来看。
INDEX(deleted_at)用于deleted_at IS NULL:
NULL。IS NULL失败。INDEX(deleted_at)未使用:
deleted_at IS NULL,否则过滤掉该行。综合指数:
拥有以 开头的“复合”(多列)索引可能非常有益deleted_at。例子:
INDEX(deleted_at, foo)
WHERE deleted_at IS NULL
AND foo BETWEEN 111 AND 222
Run Code Online (Sandbox Code Playgroud)
无论表的百分比是多少,deleted_at IS NULL这都很有可能有效地使用索引。
NULL使用和向下钻取索引 BTree 以获得第一行foo >= 111。IS NULL或foo <= 222失败。请注意,在 , 中INDEX,NULL其行为与任何其他单个值非常相似。(并且NULLs存储在其他值之前。)
我不知道为什么@NB 上面有这么多赞成票,在我的上下文中,我发现这完全不正确。
我在某些键表上为 delete_at 时间戳添加了索引,并享受了一些查询从 32 秒下降到小于 5.4 毫秒的乐趣。这实际上取决于您的应用程序的性质。
在我的场景中,我有 3 个带有软删除的表,一些简单的连接(全部带有索引),但是由于 Laravel 处理软删除的默认性质,我的查询受到了影响。
我强烈建议将这些列编入索引,这样您的应用程序就会在记录数量增加时阻塞。