25

我什么时候应该在表上使用索引?

  1. 从多少行索引才有意义?
  2. 如果我有具有恒定行的表,只是编辑了列(不在“where”子句中),即使表只有大约 15 行,索引也有意义?编辑:在这种情况下,非索引选择/读取是否比索引读取更有效?

编辑:现在我正在使用 firebird 2.5,但大多数时候我使用的是 SQL Server 2005/2008。

4

5 回答 5

40

一般来说,我的索引策略是这样的(我现在只使用 SQL Server - 根据需要适应您自己的数据库系统):

  • 选择一个好的集群键 - 不是 GUID,不是 aVARCHAR(250)或其他东西 - 一个好的集群键是窄的、唯一的、稳定的、不断增加的- 像 a 这样的东西INT IDENTITY是完美的。使它成为您的聚集主键-> 为您提供表上的第一个索引

  • 对于用作另一个表的外键的任何列 - 添加索引。它可以是单列索引 - 也可以是复合索引 - 最适合您的情况。重要的是外键列是该索引中的第一列(如果您使用的是复合索引) - 否则,JOIN您的系统将无法使用 's 或检查引用完整性的好处

现在就是这样。

然后:运行您的系统 - 观察和测量 - 建立基线。应用程序是否足够快?如果是 -> 你已经完成了 - 回家享受你的业余时间。

如果不是:然后开始收集数据和指示,说明应用程序速度不够快的原因。查看诸如 SQL Server 中的 DMV 之类的东西,它们告诉您性能最差的查询,或者缺少索引 DMV。分析那些。看看你可以改进什么。一次又一次地添加一个索引:观察、测量、与您的基线进行比较。

如果您有改进 -> 保留该索引,并且此测量是您的新基准。冲洗并重复,直到您(和您的用户)对应用程序的性能感到满意(然后回家享受您的休息时间)。

SQL Server 中的过度索引可能比没有任何索引更糟糕。不要从太多的索引开始!仅建立良好的聚集 PK 和外键非聚集索引 - 仅此而已 - 然后观察、测量、优化和重复该循环。

于 2012-08-16T10:39:49.933 回答
7

这是一个非常复杂的讨论,您必须牢记几件事。主要是您不应该根据表上的行数来考虑索引,而是根据您对其运行的查询来考虑。索引只会帮助选择查询,同时它会稍微降低插入、删除和更新的性能,因为除了更改表上的行之外,您还必须更改索引。

您似乎对这件事很陌生,所以我建议您查看您的执行计划并尝试消除所有“扫描”操作,因为它们几乎读取所有表甚至所有索引。你应该总是有寻找,但你应该平衡它与你表上的索引数量。

如果您使用的是 SQL Server,则可以使用 SQL Server profiler 运行跟踪以帮助您

编辑:

在这种情况下,非索引选择/读取是否比索引读取更有效?

是的,但是如果发生这种情况,引擎将足够聪明,不会使用索引

于 2012-08-16T10:02:08.080 回答
1

索引适用于从表中选择一小部分行。按主键值查询是对索引的最佳利用。最糟糕的情况是通过索引访问表中的所有行,因为它必须读取索引页引用的数据页。另一个例子是结果集的内存排序可能比通过排序列上的索引对结果集进行排序更快。永远不要忘记,虽然索引可以提高查询性能,但索引会降低写入性能。

有些人提到了建立基线,使用某种跟踪实用程序来衡量性能等。如果您对既定的性能感到满意,请继续。如果没有,分析执行计划,物理数据模型(可用索引),重新计算统计数据,看看是否有助于优化器选择更好的执行计划。确保 DBMS 可以(被允许)利用可用的 RAM。尽量减少磁盘 I/O 等等。

对于 Firebird 2.5,新添加的 Firebird Trace API 是天赐之物。现在,您终于可以通过性能计数器(执行计划、执行时间、I/O 统计...)获得对数据库执行的近乎实时的跟踪。Upscene Productions的第三方产品FB TraceManager使 Trace API 的使用变得愉快。

于 2012-08-16T11:12:50.257 回答
0

关于您问题的第二部分,如果一个表只有 15 行,那么无论您有多少索引,很可能总是会扫描该表,因为它太小了。

于 2012-08-16T12:14:49.693 回答
0

我使用此查询来了解哪些表需要索引:

-- Missing Indexes for current database by Index Advantage  (Query 57) (Missing Indexes)
SELECT DISTINCT CONVERT(decimal(18,2), user_seeks * avg_total_user_cost * (avg_user_impact * 0.01)) AS [index_advantage], 
migs.last_user_seek, mid.[statement] AS [Database.Schema.Table],
mid.equality_columns, mid.inequality_columns, mid.included_columns,
migs.unique_compiles, migs.user_seeks, migs.avg_total_user_cost, migs.avg_user_impact,
OBJECT_NAME(mid.[object_id]) AS [Table Name], p.rows AS [Table Rows]
FROM sys.dm_db_missing_index_group_stats AS migs WITH (NOLOCK)
INNER JOIN sys.dm_db_missing_index_groups AS mig WITH (NOLOCK)
ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details AS mid WITH (NOLOCK)
ON mig.index_handle = mid.index_handle
INNER JOIN sys.partitions AS p WITH (NOLOCK)
ON p.[object_id] = mid.[object_id]
WHERE mid.database_id = DB_ID() 
ORDER BY index_advantage DESC OPTION (RECOMPILE);

请注意,这只会给您一个北方,您仍然需要考虑上面已经回答的内容。

于 2017-06-02T19:22:18.120 回答