对于涉及表行的一小部分的查询,无论有 100
行还是 1,000,000
行,索引总是有益的。
请参阅我博客中的此条目,其中包含计划和性能详细信息的示例:
像这样的查询:
SELECT *
FROM table1 t1
JOIN table2 t2
ON t2.col = t1.col
很可能会使用 HASH JOIN
。一个小表的哈希表将被建立,并且来自大表的行将用于探测哈希表。
为此,不需要索引。
然而,这个查询:
SELECT *
FROM table1 t1
JOIN table2 t2
ON t2.col = t1.col
WHERE t1.othercol = @value
将使用 NESTED LOOPS
:从外部表(table1
)获取的行将使用一个在table1.othercol
上的索引进行搜索,并且从内部表(table2
)获取的行将使用一个在table2.col
上的索引进行搜索。
如果您没有在col1
上创建索引,将会使用 HASH JOIN
,需要扫描两个表中的所有行并使用一些额外的资源来构建哈希表。
索引也对此类查询非常有用:
SELECT t2.col
FROM table1 t1
JOIN table2 t2
ON t2.col = t1.col
如果是这种情况,引擎根本不需要读取table2
本身:这个查询所需的所有数据都可以在索引中找到,而索引可能比表本身更小、更高效地进行读取。
当然,如果你需要对数据排序,并且在table1.col
和table2.col
上都有索引,那么以下查询就非常有用:
SELECT *
FROM table1 t1
JOIN table2 t2
ON t2.col = t1.col
ORDER BY
t2.col
如果两个输入的数据集都已排序,那么查询可能会使用“合并连接(MERGE JOIN)”方法,这种方法非常快速,并且其输出也是有序的,这意味着“ORDER BY”不需要额外操作。
请注意,即使您没有索引,优化器也可能选择“Eager Spool”您的小表,这意味着在查询期间建立一个临时索引,并在查询结束后删除该索引。
如果查询很小,它将非常快速,但是再次强调,索引不会损害查询性能(指SELECT查询)。如果优化器不需要它,它就不会被使用。
请注意,创建索引可能会影响DML性能,但这是另一回事。
这取决于您的数据选择性,如果您的数据不够具有选择性,那么索引可能甚至不会被使用,因为成本太高了。如果表中只有2个值,并且这些值均匀分布,则会得到扫描而不是查找。
我仍然认为每个表都应该有一个主键,如果您有主键,那么您已经有了一个索引。
在索引的好处显现出来之前,插入操作的惩罚是可以忽略不计的。优化器在此之前会很聪明地忽略索引。所以最好一开始就为表创建索引。
索引通常会提高查询的性能,但需要额外的内存和插入/删除时的性能成本(因为此时需要维护索引)。只有分析才是确定索引是否对您的特定情况有益的唯一方法。
一般来说,创建索引时,您正在交换内存以获取速度(除了插入的额外成本)。如果您进行许多查询(选择或更新)相对于插入/删除的行数,那么索引几乎总是会增加您的性能。
最好的方法是让服务器自己来解决。您可以在有意义的列中创建索引(我确定有整章甚至整本书介绍如何以最佳方式执行此操作),然后让SQL服务器确定何时/如何使用索引。
在许多情况下,在优化时,您需要阅读特定DBMS的文档,了解它如何使用索引,并将其与您正在优化的应用程序使用的查询相关联。然后您可以微调索引使用。
我相信,一旦您开始在那些 int 字段上进行连接操作,您的表就已经足够大了。如果该表太小,无法从索引中受益,则开销不足以让您选择退出。
当我考虑索引开销时,通常会考虑表索引会因插入、删除和更新索引列而频繁更改的程度。