我经常看到人们说索引变慢了update
,delete
而且insert
。这被用作笼统的陈述,就好像它是绝对的。
在调整我的数据库以提高性能时,我不断遇到这种情况,这似乎在逻辑上与我的规则相矛盾,而且我找不到任何人以其他方式说或解释。
在 SQL Server 中,我相信/假设大多数其他 DBMS,您的索引是根据您指定的特定列创建的。插入和删除总是会影响一整行,因此它们不可能不影响索引,但更新似乎更独特,它们只能具体影响某些列。
如果我有未包含在任何索引中的列并且我更新它们,它们是否会因为我在该表中的其他列上有索引而变慢?
例如,假设在我的User
表中我有一个或两个索引,主键是一个身份/自动增量列,可能还有另一个在某个外键列上。
如果我更新一个没有直接索引的列,比如他们的电话号码或地址,这个更新是否会变慢,因为在这两种情况下我在这个表的其他列上都有索引?我正在更新的列不在索引中,所以从逻辑上讲,不应该更新索引,不是吗?如果有的话,如果我使用 WHERE 子句中的索引,我会认为它们会加快速度。
对于相对较快的现代系统,从性能的角度来看,对于绝大多数系统而言,向 OLTP 表添加单个索引可能几乎无法检测到。也就是说,您不应该创建不必要的索引,并且您可能不应该为表中的每一列创建单列索引。
您的假设是正确的,即对于许多查询,有用的索引的存在将导致非常显着的速度提高。
尽管您的问题似乎与性能有关,但添加索引还有其他几个潜在问题,包括但不限于:
在将索引添加到表中时,创建索引所需的时间可能会导致阻塞。锁的寿命很短,很可能不会造成大问题。
索引更改会导致任何引用基础表的计划的执行计划无效。当重新编译这些执行计划时,某些查询的性能可能会发生负面变化。
索引修改可能会导致查询返回以前没有返回的错误。以用于返回 varchar 字段中包含的日期的过滤索引为例;如果过滤器消除了任何不是日期的行,并且随后更改了该过滤器,则依赖该索引的查询现在在尝试转换非日期数据时可能会失败。
新的索引可能会导致执行顺序发生变化,从而导致之前未发生的可能发生死锁。
Microsoft 的索引设计指南是关于上述几点的一个很好的资源。
您是正确的,更新非索引列不会导致索引更改。在一个简单的情况下,也不会对桌子产生整体影响。
如果查询可以使用索引来查找数据,它可能会加快查找速度,但确切的行为(取决于您的 SQL 品牌)可能与其他品牌的 SQL 不同。(我主要使用 Microsoft SQL Server。)
当然,使用大量数据更新列可能会导致某些行移动到不同的页面,等等。
对非索引列的更新不会修改索引,即使数据行由于更新而被移动,因为转发记录保留在原地。
因此,更新不会受到任何惩罚。
如果更新操作针对固定大小的非索引列(如整数),一般来说应该不会很慢,但与 select 语句相比,更新最终也必须写入慢速磁盘。