拉威尔';s";软删除;需要MySQL上的索引吗?
如果我在Laravel4.2中使用软删除(数据库是mysql),那么每个有说服力的查询都有拉威尔';s";软删除;需要MySQL上的索引吗?,mysql,laravel,optimization,indexing,eloquent,Mysql,Laravel,Optimization,Indexing,Eloquent,如果我在Laravel4.2中使用软删除(数据库是mysql),那么每个有说服力的查询都有其中deleted\u at为NULL。在处的已删除\u上没有索引 在大桌子上会慢吗?(或者可能为空在不需要索引的情况下进行了优化) 我是否应该在列的deleted\u上添加索引 那么,Laravel的“soft_delete”列中的deleted_是否需要MySQL中的索引 澄清:Laravel在的deleted\u列中存储一个时间戳,以指示记录何时被软删除,而不是布尔值。位于的deleted\u列不
其中deleted\u at为NULL
。在处的已删除\u上没有索引
- 在大桌子上会慢吗?(或者可能
为空
在不需要索引的情况下进行了优化)
- 我是否应该在
列的deleted\u上添加索引李>
那么,Laravel的“soft_delete”
列中的deleted_是否需要MySQL中的索引
澄清:Laravel在
的deleted\u列中存储一个时间戳,以指示记录何时被软删除,而不是布尔值。位于
的deleted\u列不是一个好的索引候选。与注释相比,我将尝试更好地解释:索引只有在基数相对较高时才有用。基数是描述数据集中索引唯一性的数字。这意味着它是总记录数除以总唯一记录数
例如,主键的基数是1。每个记录都包含主键的唯一值。1也是最高的数字。你可以把它看作是“100%”。
但是,诸如deleted_at之类的列没有这样的值。Laravel对deleted_at所做的是检查它是否为空。这意味着它有两个可能的值。包含两个值的列具有极低的基数,随着记录数的增加而减少
您可以为这样的列编制索引,但它没有任何帮助。将会发生的是,它可能会减慢速度并占用空间
TL;DR:不,您不必为该列编制索引,索引将不会对性能产生有益影响。我不知道@N.B.的上述内容为什么有这么多的上升票,在我的上下文中,我发现这完全不正确
我在一些keys表的时间戳处向deleted_添加了索引,并享受了一些从32秒下降到5.4毫秒以下的查询。这实际上取决于应用程序的性质
在我的场景中,我有3个带有软删除的表,一些简单的连接(都带有索引),但由于Laravel处理软删除的默认性质,我的查询受到了影响
我强烈建议为这些列编制索引,这样当记录数字上升时,你的应用程序就不会阻塞
简短的回答:也许吧
长答覆:
如果deleted\u at
中几乎没有不同的值,MySQL将不会使用索引(deleted\u at)
如果在deleted\u at
中有不同的非空日期,MySQL将使用索引(deleted\u at)
到目前为止,大多数讨论都没有考虑到这个单列索引的基数
注意:这与2值标志不同,例如已删除
。在这样的数据库上使用单列索引是没有用的
更多讨论(从MySQL的角度)
说
现在,当您在模型上调用delete方法时,deleted_at列将设置为当前日期和时间。并且,当查询使用软删除的模型时,软删除的模型将自动从所有查询结果中排除
因此,我假设这发生在表定义中:
deleted_at DATETIME NULL -- (or TIMESTAMP NULL)
并且该值被初始化(显式或隐式)为NULL
案例1:大量新行,尚未“删除”:所有deleted\u at
值均为NULL
。在这种情况下,优化器将避开索引(已删除)
,认为这没有帮助。事实上,使用索引会带来伤害,因为遍历整个索引和数据的成本会更高。忽略索引并简单地假设所有行都是选中的候选行
,这样会更便宜
案例2:删除了几行(很多行中的几行):现在deleted\u at
有多个值。尽管Laravel只关心是否为空
vs是否为非空
,但MySQL将其视为一个多值列。但是,由于测试的为NULL
,并且大多数行仍然是NULL
,因此优化器的反应与案例1相同
案例3:软删除的行比仍处于活动状态的行多得多:现在索引突然变得有用,因为表中只有一小部分为NULL
案例2和案例3之间没有确切的界限。20%是一个方便的经验法则
现在,从执行的角度来看。
用于删除位置的索引(已删除位置)
为空
:
使用NULL
向下钻取第一行的索引BTree
扫描直到为空
失败
对于每个匹配的行,进入数据树以获取该行
索引(已删除)
未使用:
扫描数据树(或使用其他索引)
对于每个数据行,检查deleted\u at是否为NULL
,否则过滤掉该行
综合指数:
在
处有一个以deleted\u开头的“复合”(多列)索引可能非常有益。例如:
INDEX(deleted_at, foo)
WHERE deleted_at IS NULL
AND foo BETWEEN 111 AND 222
这很可能有效地使用索引,而不管表中已删除的百分比是多少\u at为NULL
使用NULL
和foo>=111
向下钻取第一行的索引BTree
扫描直到为空
或foo它不需要索引。如果为空,则不会删除它。如果它有一个值,它将被删除。这意味着它有两个可能的值才能工作。具有两个可用值的列不是很好的索引候选列-它们的基数正在收敛到0。因此,删除的_at不需要索引。好的,谢谢。我认为几乎每个where
子句都需要索引。如果您愿意,可以将您的评论作为答案发布。这是否意味着没有理由为布尔列编制索引,或者我误解了吗?@Cabloo-您没有