简短回答:也许。
长答案:
如果deleted_at 中的不同 值很少,MySQL 将不会使用INDEX(deleted_at)。
如果deleted_at 中有不同的非空日期,MySQL 将使用INDEX(deleted_at)。
(到目前为止)大多数讨论都没有考虑到这个单列索引的基数。
注意:这与 is_deleted 这样的 2 值标志不同。 在此类上设置单列索引是没有用的。
更多讨论(从 MySQL 的角度)
https://laravel.com/docs/5.2/eloquent#soft-deleting 说
现在,当您在模型上调用 delete 方法时,deleted_at 列将被设置为当前日期和时间。并且,当查询使用软删除的模型时,软删除的模型将自动从所有查询结果中排除。
据此,我假设这发生在表定义中:
deleted_at DATETIME NULL -- (or TIMESTAMP NULL)
并且值被初始化(显式或隐式)为NULL。
案例 1:许多新行,尚未“删除”:所有 deleted_at 值都是 NULL。在这种情况下,优化器会避开INDEX(deleted_at),因为它没有帮助。事实上,使用索引会受到伤害,因为遍历整个索引和数据会花费更多。忽略索引并简单地假设所有行都是SELECTed 的候选者会更便宜。
案例 2:删除了几行(多行):现在 deleted_at 有多个值。虽然 Laravel 只关心 IS NULL 与 IS NOT NULL,但 MySQL 将其视为多值列。但是,由于测试是针对IS NULL 并且大多数行仍然是NULL,因此优化器的反应与案例1 相同。
案例 3:软删除的行多于仍然处于活动状态的行:现在索引突然变得有用,因为只有一小部分表 IS NULL。
案例 2 和案例 3 之间没有确切的分界线。20% 是一个方便的经验法则。
现在,从执行的角度来看。
INDEX(deleted_at) 用于deleted_at IS NULL:
- 使用
NULL 向下钻取第一行的索引 BTree。
- 扫描直到
IS NULL失败。
- 对于每个匹配的行,进入 data BTree 以获取该行。
INDEX(deleted_at) 未使用:
- 扫描数据 BTree(或使用其他索引)
- 对于每个 data 行,检查
deleted_at IS NULL,否则过滤掉该行。
复合索引:
可能有一个以deleted_at 开头的“复合”(多列)索引。示例:
INDEX(deleted_at, foo)
WHERE deleted_at IS NULL
AND foo BETWEEN 111 AND 222
这很有可能有效地使用索引无论表中有多少百分比有deleted_at IS NULL。
- 使用
NULL 和foo >= 111 向下钻取第一行的索引BTree。
- 扫描直到
IS NULL 或foo <= 222 失败。
- 对于每个匹配的行,进入 data BTree 以获取该行。
请注意,在INDEX 中,NULL 的行为与任何其他单个值非常相似。 (并且NULLs 存储在其他值之前。)