14

我正在将巴西股市数据导入 SQL Server 数据库。现在我有一张表格,其中包含三种资产的价格信息:股票、期权和远期。我还在 2006 年的数据中,该表有超过 50 万条记录。我有更多 12 年的数据要导入,因此该表肯定会超过一百万条记录。

现在,我的第一种优化方法是将数据保持在最小大小,因此我将行大小减少到平均 60 字节,并包含以下列:

[股票] [int] 非空
[日期] [smalldatetime] 非空
[打开] [smallmoney] 非空
[高] [smallmoney] 非空
[低] [smallmoney] 非空
[关闭] [smallmoney] 非空
[交易] [int] 非空
[数量] [bigint] 非空
[数量] [钱] NOT NULL

现在,第二种优化方法是创建一个聚集索引。实际上主索引是自动聚集的,我把它做成了一个包含 Stock 和 Date 字段的复合索引。这是独一无二的,我不能在同一天拥有同一股票的两个报价数据。

聚集索引确保来自同一股票的报价保持在一起,并且可能按日期排序。第二个信息是真的吗?

现在有 50 万条记录,从特定资产中选择700条报价大约需要 200毫秒。我相信随着桌子的增长,这个数字会越来越高。

现在对于第三种方法,我正在考虑将表格分成三个表格,每个表格用于特定市场(股票、期权和远期)。这可能会将表格大小减少 1/3。现在,这种方法会有所帮助还是无关紧要?现在,该表的大小为 50mb,因此它可以完全放入 RAM 中而没有太多麻烦。

另一种方法是使用 SQL Server 的分区功能。我对此了解不多,但我认为它通常在表很大并且您可以跨越多个磁盘以减少 I/O 延迟时使用,对吗?在这种情况下,分区会有所帮助吗?我相信我可以对不同表中的最新值(最近年份)和最旧值进行分区,寻找最新数据的概率更高,并且使用小分区可能会更快,对吧?

还有什么其他的好方法可以使这个过程尽可能快?该表的主要选择用途是从特定资产中查找特定范围的记录,例如资产 X 的最近 3 个月。还有其他用途,但这将是最常见的,可能执行超过 3k用户同时。

4

9 回答 9

11
  1. 在 100 万条记录中,我不会认为这是一个特别大的表,需要不寻常的优化技术,例如拆分表、非规范化等。但是当你尝试了所有不影响你的正常方法时,这些决定就会出现使用标准查询技术的能力。

现在,第二种优化方法是创建一个聚集索引。实际上主索引是自动聚集的,我把它做成了一个包含 Stock 和 Date 字段的复合索引。这是独一无二的,我不能在同一天拥有同一股票的两个报价数据。

聚集索引确保来自同一股票的报价保持在一起,并且可能按日期排序。第二个信息是真的吗?

这在逻辑上是正确的 - 聚集索引定义了磁盘上记录的逻辑顺序,这是您应该关心的全部。SQL Server 可能会放弃在物理块内进行排序的开销,但它仍然会表现得好像这样做了,所以它并不重要。在任何情况下,查询一只股票可能会读 1 或 2 页;并且优化器不会从页面读取中的无序数据中受益匪浅。

现在有 50 万条记录,从特定资产中选择 700 条报价大约需要 200 毫秒。我相信随着桌子的增长,这个数字会越来越高。

不一定显着。表大小和查询速度之间没有线性关系。通常有更多更重要的考虑因素。在你描述的范围内,我不会担心它。这就是你担心的原因吗?在我看来,200 毫秒已经很棒了,足以让您达到加载表格的程度,您可以开始进行实际测试,并更好地了解现实生活中的性能。

现在对于第三种方法,我正在考虑将表格分成三个表格,每个表格用于特定市场(股票、期权和远期)。这可能会将表格大小减少 1/3。现在,这种方法会有所帮助还是无关紧要?现在,该表的大小为 50mb,因此它可以完全放入 RAM 中而没有太多麻烦。

No! This kind of optimization is so premature it's probably stillborn.

Another approach would be using the partition feature of SQL Server.

Same comment. You will be able to stick for a long time to strictly logical, fully normalized schema design.

What would be other good approachs to make this the fastest possible?

The best first step is clustering on stock. Insertion speed is of no consequence at all until you are looking at multiple records inserted per second - I don't see anything anywhere near that activity here. This should get you close to maximum efficiency because it will efficiently read every record associated with a stock, and that seems to be your most common index. Any further optimization needs to be accomplished based on testing.

于 2008-12-13T23:54:54.503 回答
10

一百万条记录真的没有那么大。听起来确实搜索时间太长了-您要搜索的列是否已编入索引?

与以往一样,第一个调用端口应该是 SQL 分析器和查询计划评估器。询问 SQL Server 它将如何处理您感兴趣的查询。我相信您甚至可以要求它提出更改建议,例如额外的索引。

我还没有开始进入分区等 - 正如你所说,它现在应该都舒服地放在内存中,所以我怀疑你的问题更有可能是缺少索引。

于 2008-12-03T16:32:18.410 回答
3

首先检查您对该查询的执行计划。确保您的索引正在被使用。我发现了。一百万条记录并不多。为了给出一些观点,我们有一个包含 3000 万行的库存表,我们的整个查询连接了大量的表并进行了大量计算,可以在 200 毫秒以下运行。我们发现在quad proc 64 位服务器上,我们可以有更多的记录,所以我们从不打扰分区。

您可以使用 SQL Profier 查看执行计划,或者只从 SQL Management Studio 或查询分析器运行查询。

于 2008-12-03T16:35:18.920 回答
3

重新评估索引...这是最重要的部分,数据的大小并不重要,它确实如此,但不完全是出于速度目的。

我的建议是为该表重新构建索引,为您最需要的列创建一个复合索引。现在您只有几条记录使用不同的索引,否则一旦您将所有历史数据都放在表中,尝试新事物会很烦人。

在你检查你的查询之后,让查询计划评估器成为你的朋友,并检查引擎是否使用了正确的索引。

我刚刚读了你上一篇文章,我不明白一件事,你在插入数据时正在查询表?同时?。做什么的?通过插入,您的意思是一条记录还是数十万条记录?你怎么插入?逐个?

但同样的关键是索引,不要搞乱分区和东西..特别是有百万记录,那没什么,我有 150 万条记录的表,返回 40k 特定记录需要引擎大约 1500 毫秒.. .

于 2008-12-03T16:52:08.933 回答
1

我在一个学区工作,我们必须跟踪每个学生的出勤率。这就是我们赚钱的方式。我保存每个学生每日出勤分数的表目前有 3890 万条记录。我可以由此快速提高单个学生的出勤率。我们在这张表上保留了 4 个索引(包括主键)。我们的聚集索引是学生/日期,它保存所有学生的记录。如果插入学生的旧记录,我们已经对该表的插入进行了打击,但对于我们的目的而言,这是一个值得冒险的风险。

关于选择速度,我当然会在您的情况下利用缓存。

于 2008-12-03T16:35:04.723 回答
1

您已经提到您的主键是 (Stock, Date) 上的复合键,并且是聚集的。这意味着该表按 Stock 和 Date 进行组织。每当您插入新行时,它都必须将其插入到表格的中间,这可能会导致其他行被推到其他页面(页面拆分)。

我建议尝试将主键反转为 (Date, Stock),并在 Stock 上添加非聚集索引以方便快速查找特定 Stock。这将允许插入始终发生在表的末尾(假设您按日期顺序插入),并且不会影响表的其余部分,并且页面拆分的可能性较小。

于 2008-12-03T22:41:42.253 回答
0

执行计划显示它使用聚集索引非常好,但我忘记了一个非常重要的事实,我仍在插入数据!插入可能过于频繁地锁定表。有没有办法我们可以看到这个瓶颈?

执行计划似乎没有显示任何有关锁定问题的信息。

现在这些数据只是历史数据,当导入过程完成时,插入将停止并且频率要低得多。但是我很快就会有一个更大的实时数据表,它会遇到这个不断插入的问题,并且会比这张表大。因此,任何优化这种情况的方法都非常受欢迎。

于 2008-12-03T16:47:01.547 回答
0

另一种解决方案是为每年创建一个历史表,并将所有这些表放入历史数据库中,填写所有这些表,然后为它们创建适当的索引。完成此操作后,您将无需再触摸它们。为什么你必须继续插入数据?要查询所有这些表,您只需“合并”它们:p

当前年份表应该与这个历史表有很大不同。据我所知,您打算在旅途中插入记录?,我会计划一些不同的事情,比如每天不时进行批量插入或类似的事情。当然,这一切都取决于你想做什么。

这里的问题似乎出在设计上。我会去一个新的设计。你现在拥有的那个我理解它不适合。

于 2008-12-03T17:03:55.210 回答
0

实际上主索引是自动聚集的,我把它做成了一个包含 Stock 和 Date 字段的复合索引。这是独一无二的,我不能在同一天拥有同一股票的两个报价数据。

聚集索引确保来自同一股票的报价保持在一起,并且可能按日期排序。第二个信息是真的吗?

SQL Server 中的索引始终按索引中的列顺序排序。因此,[stock,date] 上的索引将首先按股票排序,然后在按日期排序。[日期,股票] 上的索引将首先按日期排序,然后在股票日期内排序。

在进行查询时,您应该始终在 WHERE 部分中包含索引的第一列,否则无法有效地使用索引。

对于您的具体问题:如果股票的日期范围查询是最常见的用法,则在 [date, stock] 上执行主键,因此数据将按日期顺序存储在磁盘上,您应该获得最快的访问。根据需要建立其他索引。插入大量新数据后进行索引重建/统计更新。

于 2008-12-13T22:58:18.673 回答