我的 SQL 知识有限,所以我将使用的术语很可能不是正确的。
我有一张表可以存储多个位置的测试结果。
测试将记录在不同位置的不同数据库中(无网络连接),“主”位置将定期从其他位置“导入”测试结果。
我计划按顺序在 LocationId (int) 和 Date (datetime) 列上有一个聚集的复合主键。原因是它应该将一个位置的所有结果保存在一起,我几乎不会按日期范围进行查询,而是按日期范围和位置进行查询。
行大小为 80 到 100 字节,测试结果的数量不应超过几百万。典型的“导入”将插入来自另一个位置的 50 到 10 万个结果。
进口期间会发生什么?SQL 会“移动”现有的行来维护集群,还是会让表变得“碎片化”?如果一次导入一行,这是否会对性能造成很大影响?我是否应该不理会行的顺序,而只是添加一个标识列作为主键并在 Date 列上添加一个索引来帮助我的查询?
天哪,你这里有很多问题。让我们分解一下。
问:SQL 会“移动”现有的行来维护集群,还是会让表变得“碎片化”?
将数据库视为页面的集合 - 放在您办公桌上的字面纸片。现在想想字典。如果您想在字典中添加更多单词,如果页面有空白空间,您可以将它们添加到位。
当您第一次从空字典开始时,这相对容易。但是想想一本成熟的字典,里面有成千上万的纸页,全是满的。
当您想向该成熟词典添加更多单词时,页面上可能不会留下任何空间。SQL Server 会“撕掉”一个页面——它会在别处取一个全新的页面,并将一些单词移到那个新页面上。新页面将位于字典的末尾。好消息是,在此操作之后,您的字典末尾和中间现在都有一个半空的页面,两者都有空间来添加单词。
如果您碰巧按此顺序添加它们,那就是。(这就是为什么加载数据的方式变得越来越重要的原因。)
如果一次导入一行,这是否会对性能造成很大影响?
暂时忘记索引 - 无论索引结构如何,一次添加一行数据都是低效的。SQL Server 是一个基于集合的系统——只要您可以在集合中工作,您就应该这样做。
当我查询数据时会发生什么?
这不是你问的,是我替你问的,哈哈哈。
回想一下我们插入的后果。现在我们有了一本大部分是有序的字典,但是当你到达字典的几个点时,你必须跳到后面从其他几页开始阅读。如果这些页面都缓存在您的内存中(RAM、缓冲池等),那么开销就不会那么大。无论如何,大多数内存访问都是随机的——它不像 SQL Server 将字典按顺序存储在内存中。
另一方面,如果您需要从传统的磁性硬盘驱动器(旋转生锈)中获取数据,那么如果这些数据按顺序存储,您最终可以获得一些性能优势。然而,这里真正的设计目标是从 RAM 中获取数据,而不是从驱动器中获取数据。磁盘上的碎片整理数据与磁盘上的碎片数据之间的差异远不及从磁盘获取数据与从 RAM 获取数据之间的差异那么显着。
我是否应该不理会行的顺序,而只是添加一个标识列作为主键并在 Date 列上添加一个索引来帮助我的查询?
Bingo:这是物理数据库设计和逻辑数据库设计的区别。程序员最初必须非常担心物理数据库设计,但只要您的数据库大小低于 100GB,您就可以在后期修复逻辑设计。在那里为初学者放置一个标识字段,在其上进行集群,然后在运行几个月后,重新访问索引设计以最大限度地提高性能。
现在,话虽如此,一旦您对这种类型的决策有经验,那么您将更有能力从一开始就猜测索引。即便如此,最初我什至通常都不会在索引设计上花太多心思。用户似乎从来没有像我预期的那样查询数据。