SQL 服务器索引设计,其中 PK 与行数据大小相同
SQL Server index design where PK would be same size as row data
我正在尝试确认我的 table 需要一个主键,即使它会使行大小加倍,或者弄清楚什么是合适的索引策略。我们正在使用 SQL Server 2008 R2。
我有一个 Testscores
table 超过 20 亿行,每行只包含以下形式的 10 个字节的数据:
(ItemID INT, ProjectID SMALLINT, DepartmentID SMALLINT, Score REAL).
没有列是唯一的,但我们有大约 1 亿个 ItemID、500 个 ProjectID 和 300 个 DepartmentID。
我在 Projects
中查找了 table,其中包含 ~500 行,格式如下
(ID SMALLINT, ProjectName varchar, State Char(2), year INT)
最初这个 table 是非规范化的,大约 600gb。我的目标是能够在 ProjectName
、State
或年份(有时是其中一个,有时是两个,有时是三个)查询项目 table。然后我会在 ProjectsID
上加入 Testscores
table 到 return 来自匹配项目的所有测试分数(大约在 500 万到 2000 万个结果之间)
在重建 tables 之后(愚蠢的人应该首先想到这一点),我开始了解到如果没有聚簇索引,每个查询都必须使用 table 扫描,即使我在 ProjectsID
上构建非聚集索引。
我当前的行大小是 10 个字节,添加一个 BigInt
(需要,已经达到 20 亿并且还在增加)将为每行添加 8 个字节,基本上使我的数据库增加一倍。在 ProjectsID
上构建非聚集索引基本上需要 8 个字节用于唯一标识符(4 个用于值,4 个因为它是第一个 varchar)。
有什么想法吗?我在数据库设计中搞砸了吗?我不介意再次重建它,我只是想把它做好。
PS,我纠结了快十年了,这是我遇到的第一个无法通过搜索回答的问题。你们都摇滚!
编辑:当我将数据加载到 table 时,它是在 ProjectID ASC, ItemID ASC
上预先排序的,如果这有什么不同的话。
对于每条记录 8 字节的记录大小,SQL 服务器在每页上放置大约 1,000 行。这意味着任何选择超过 0.1% 数据的查询很可能会访问所有或几乎所有页面。在这些情况下,引擎通常会选择完整 table 扫描而不是使用索引。
鉴于您的查询至少返回 500 万行,我推测很难避免完整的 table 扫描。聚簇索引可能对某些查询有帮助(也许通过一些奇迹),但并非对所有查询都有帮助。
对 table 进行分区可能会有帮助;但是,您需要对数据进行非规范化以进行有效分区。
我正在尝试确认我的 table 需要一个主键,即使它会使行大小加倍,或者弄清楚什么是合适的索引策略。我们正在使用 SQL Server 2008 R2。
我有一个 Testscores
table 超过 20 亿行,每行只包含以下形式的 10 个字节的数据:
(ItemID INT, ProjectID SMALLINT, DepartmentID SMALLINT, Score REAL).
没有列是唯一的,但我们有大约 1 亿个 ItemID、500 个 ProjectID 和 300 个 DepartmentID。
我在 Projects
中查找了 table,其中包含 ~500 行,格式如下
(ID SMALLINT, ProjectName varchar, State Char(2), year INT)
最初这个 table 是非规范化的,大约 600gb。我的目标是能够在 ProjectName
、State
或年份(有时是其中一个,有时是两个,有时是三个)查询项目 table。然后我会在 ProjectsID
上加入 Testscores
table 到 return 来自匹配项目的所有测试分数(大约在 500 万到 2000 万个结果之间)
在重建 tables 之后(愚蠢的人应该首先想到这一点),我开始了解到如果没有聚簇索引,每个查询都必须使用 table 扫描,即使我在 ProjectsID
上构建非聚集索引。
我当前的行大小是 10 个字节,添加一个 BigInt
(需要,已经达到 20 亿并且还在增加)将为每行添加 8 个字节,基本上使我的数据库增加一倍。在 ProjectsID
上构建非聚集索引基本上需要 8 个字节用于唯一标识符(4 个用于值,4 个因为它是第一个 varchar)。
有什么想法吗?我在数据库设计中搞砸了吗?我不介意再次重建它,我只是想把它做好。
PS,我纠结了快十年了,这是我遇到的第一个无法通过搜索回答的问题。你们都摇滚!
编辑:当我将数据加载到 table 时,它是在 ProjectID ASC, ItemID ASC
上预先排序的,如果这有什么不同的话。
对于每条记录 8 字节的记录大小,SQL 服务器在每页上放置大约 1,000 行。这意味着任何选择超过 0.1% 数据的查询很可能会访问所有或几乎所有页面。在这些情况下,引擎通常会选择完整 table 扫描而不是使用索引。
鉴于您的查询至少返回 500 万行,我推测很难避免完整的 table 扫描。聚簇索引可能对某些查询有帮助(也许通过一些奇迹),但并非对所有查询都有帮助。
对 table 进行分区可能会有帮助;但是,您需要对数据进行非规范化以进行有效分区。