我正在使用aspnet-core,ef-core和sql server。我有一个'订单'实体。因为我期望订单表很大,而且最常见的查询只能获得某些客户的活动订单(活动订单只占整个表的一小部分)我喜欢优化查询的速度但是我可以从这两种方法中决定:
1)我不知道这是否可行,因为我之前没有这样做,但我正在考虑创建一个名为'IsActive'的布尔列并使其成为索引,因此在查询时只有Active订单会更快
2)当订单变为未激活时,将订单移至另一个表格,即HistoricalOrders,从而使订单表保持较小。
两者中的哪一个会有更好的结果?或者这些都不是一个好的解决方案,可以建议第三种方法?
答案 0 :(得分:0)
如果要分割冷数据,那么前导布尔索引列是执行此操作的有效方法。必须将该列添加到要进行热/冷分区的所有索引。这包括聚集索引。这很尴尬。查询优化器要求您添加虚拟谓词where IsActive IN (0, 1)
,以使其能够仍然在此类索引上进行搜索。当然,现在这也会触及冷数据。因此,您可能需要了解IsActive
的具体值或首先尝试1
值,并确保它在99%的时间内匹配。
根据架构,这可能是不切实际的。我从未见过这样的好案例,但我确信它存在。
另一种方法是使用分区。在这里,查询优化器无论如何都用于探测多个分区,但你又不想让它探测冷数据。即使它没有找到任何东西,这也会将页面拉入内存,使得分区没有实际意义。
历史表的想法(例如HistoricalOrders
)在不同的服装中是相同的。
所以为了完成这项工作,你需要:
我认为(2)在大多数情况下都会杀死它。
在3种解决方案中,我可能会选择索引解决方案,因为它最简单。如果你担心人们总是通过写错误的查询来犯错误,我会选择一个单独的表格。这会让错误变得很难,但会让代码变得很尴尬。
请注意,许多索引已经自然分区。标识列或不断增加的日期时间列上的索引最后很热,其他地方很冷。 (OrderStatus INT, CreateDateTime datetime2)
上的索引每个订单状态会有一个热点,否则会冷。所以这些已经解决了。
答案 1 :(得分:-2)
在考虑新表HistoricalOrders
之前,只需创建一个列名IsActive
并使用您的数据对其进行测试。您不需要将其作为索引列.B' cos索引会占用存储空间并且会减慢写入和更新速度。所以我们在创建索引时必须非常小心。当您查询数据时,请执行以下操作。在下面的查询中,数据选择(或过滤器)在SQL srever side(IQueryable
)。所以它非常快。
注意:也使用AsNoTracking()
。它也会提升性能。
var activeOrders =_context.Set<Orders>().Where(o => o.IsActive == true).AsNoTracking()
.ToList();
参考: AsNoTracking()