1

背景

我正在将应用程序从包含 0.5-13 亿条记录的单个事件表的模式迁移到具有 30-180 个相同基础表的分区视图,每个基础表都包含该记录数的一小部分,这大大缓解了围绕管理和查询那么多记录。我使用分区视图而不是表分区,因为并非所有用户都可以访问 SQL Server 2012 的Awesome Edition

分区函数基于事件当天的笛卡尔积和事件的一个属性。换句话说,2015 年 6 月 1 日的所有事件都进入了类似“Event20150601_foo”的表中,所有具有属性“bar”的事件进入了“Event20150601_bar”,并且对于接下来的一天,事件将进入“Event20150602_foo”和“Event20150602_bar”等。通常有 2-3 个属性值和 15-60 天的事件,映射到 30-180 个不同表的典型范围。

每个表的基本结构是由 EventId (bigint) 和 PartitionKey (int) 组成的复合聚集主键,后跟一些其他未索引的列。EventId 是唯一的,在所有表中单调递增,并按顺序实现。PartitionKey 对于每个分区表都是唯一的,因此每个表的检查约束只是“CHECK (PartitionKey = x)”,其中 x 是每个分区表定义的。即使我无法提供分区键来缩小搜索范围,这也允许我通过聚集索引搜索来搜索 EventId。在我可以同时提供 EventId 和 PartitionKey 的情况下,查询非常有效,因为优化器可以只在与分区键匹配的单个表上执行索引查找,这是一个很大的性能提升。

实验

如果我可以根据事件发生的日期和更广泛的属性组合(500-5000 而不是前面提到的 2-3)进行更细化和分区,这将使我的生活更加轻松,这将需要我在范围为 10,000-50,000 个不同的分区。我在一个包含 20,000 个不同表的数据库上对此进行了测试,不幸的是,我发现不同操作的运行时间随着表数量的增加而以高于线性的速度增长。根据查询统计,大部分时间都花在了解析和编译查询上,而不是执行查询上。

以下是我发现的不同操作的运行时间(请原谅基本表):

  • 创建分区视图
    • 100 tables : 50ms
    • 1000 tables : 800ms
    • 2000 tables : 2,660ms
    • 4000 tables : 10,000ms
    • 16000 tables: 225,000ms
  • select * from PartitionedView where EventId = x(扫描所有表)
    • 100 tables : 78ms parse/compile time; 25ms exec time
    • 1000 tables : 3,500ms parse/compile time; 160ms exec time
    • 2000 tables : 15,000ms parse/compile time; 500ms exec time
    • 4000 tables : 68,000ms parse/compile time; 2,000ms exec time
    • 16000 tables:解析/编译时间超过 10 分钟后取消!
  • select * from PartitionedView where (EventId = x) and (PartitionKey = y)(只扫描一张表)
    • 100 tables : 74ms parse/compile time; 1ms exec time
    • 1000 tables : 2,500ms parse/compile time; 15ms exec time
    • 2000 tables : 11,000ms parse/compile time; 10ms exec time
    • 4000 tables : 50,000ms parse/compile time; 16ms exec time
    • 16000 tables:解析/编译时间超过 10 分钟后取消!

问题

我应该因为考虑使用那么多桌子而被责骂吗?如果没有,当存在大量表时,有没有办法可以减少查询解析和编译时间?

4

0 回答 0