加入表索引性能改进问题

时间:2014-10-15 13:31:31

标签: sql sql-server entity-framework join indexing

首先,我有三个表,都有一个主键和一些其他数据。这些表连接在一个约7000万行的连接表中: 表1,表2,表_3。

此联接表中有Table_3_Id, Table_1_Id, Table_2_Id的主键(按此顺序)。在Table_1_Id, Table_2_Id, Table_3_Id之上还有一个非聚集索引(按此顺序),填充索引为95.

数据由Table_1_Id(我预设了约100个这些ID)和(通过连接)过滤,具有Table_3的属性(因此它使用Table_3_Id)。然后,返回Table_1_Id和Table_2_Id值。这都是在实体框架中的一个查询中完成的。

这是查询:

  var items = dataContext.TablesJoin.AsNoTracking()
             .Join(dataContext.Table_3.AsNoTracking(), x => x.Table_3_Id, x => x.Id, (combi, scan) => new { combi, scan })
             .Where(x => possibleIds.Contains(x.combi.Table_1_Id) && otherIds.Contains(x.scan.Other_Id))
             .Select(x => new { FirstId = x.combi.Table_1_Id, SecondId = x.combi.DeviceInformationDevices_Id })
              ToList();

因为这是在SQL Server Express上运行的配置,所以我遇到了一些空间问题(10GB是最大的)。数据大约为2GB,但主键和索引总共为5GB。因为数据库中还有更多数据,所以我有兴趣在保持性能的同时减小索引的大小。

在查看完所有内容之后,我对使用的内容产生了一些担忧。由于连接,我不完全确定将Table_3_Id包含在非聚集索引中是多么有用。从索引中删除此列可节省大约1GB的空间。

最初,我将此表作为聚簇索引(对于安全空间)但由于该表具有相当多的插入量(1000 /小时),因为所有磁盘访问都非常慢,因为它必须不断地交换周围10GB的数据。如果将填充因子设置得更低(如70)来解决这个问题会有帮助吗?当然,它也意味着更多的浪费空间,但如果这可以在索引上节省很多,那么它可能值得吗?

这个表经常被使用,并且为了性能,需要索引。没有索引运行它需要几分钟才能执行,而索引则在2秒内完成。

执行计划xml:http://pastebin.com/raw.php?i=tfUxgYrK

1 个答案:

答案 0 :(得分:1)

您不需要唯一性的主键。您的NCI已经提供了这种独特性。你可以摆脱其中一个索引。这应该可以节省一些空间。

您可以通过使其聚集来保存其他索引使用的空间。您注意到由于显然随机定位的插入物导致的性能问题。这似乎是合理的。请考虑更改索引的列顺序,以便插入仅在一个或几个位置发生。这样,所有受影响的页面都会被缓存。 DML所需的工作集很低。

DML性能问题可能不是由于页面拆分造成的。这些主要导致CPU负载和碎片。 perf问题可能是因为必须从磁盘读取随机页面。

每小时1000次插入不是很多。考虑将写入累积到小型且完全缓存的增量表中。在后台进程中将行移动到主表。这样,DML延迟就不在关键路径上了。选择可能需要容忍陈旧或UNION ALL增量表。