我应该设计一个主键为 varchar 还是 int 的表?

2023-11-30

我知道这是主观的,但我想了解人们的意见,并希望在设计 sql server 表结构时可以应用一些最佳实践。

我个人认为,在固定(最大)长度的 varchar 上键入表是不行的,因为这意味着必须在使用它作为外键的任何其他表上传播相同的固定长度。使用int,将避免必须在整个板上应用相同的长度,这必然会导致人为错误,即 1 个表有varchar (10), 和另一个varchar (20).

这对于最初的设置来说听起来像是一场噩梦,而且意味着未来的表维护也很麻烦。例如,假设键控 varchar 列突然变成 12 个字符而不是 10 个。您现在必须去更新所有其他表,这可能是多年后的一项艰巨任务。

我错了吗?我在这里错过了什么吗?我想知道其他人对此有何看法,以及坚持使用 int 作为主键是否是避免维护噩梦的最佳方法。


选择主键时通常也会选择聚集键。他们两个经常被混淆,但你必须理解其中的区别。

主键有逻辑性business元素。主键被你的应用程序用来标识一个实体,关于主键的讨论主要是是否使用自然键 or 代理键。这些链接更详细,但基本思想是自然键源自现有的实体属性,例如ssn or phone number,而代理键对于业务实体没有任何意义,例如id or rowid他们通常是这样的类型IDENTITY或某种 uuid。我个人的观点是,代理键优于自然键,并且选择应该始终是仅限本地应用程序的身份值,以及任何类型的分布式数据的指南。主键在实体的生命周期内永远不会改变。

聚集键是定义表中行的物理存储的键。大多数时候它们与主键(逻辑实体标识符)重叠,但这实际上并没有强制执行或要求。当两者不同时,意味着表上存在实现主键的非聚集唯一索引。聚集键值实际上可以在行的生命周期内发生变化,从而导致该行在表中物理移动到新位置。如果必须将主键与聚集键分开(有时确实如此),那么选择一个好的聚集键比选择主键要困难得多。驱动集群键设计的主要因素有两个:

  1. 流行的数据访问模式.
  2. The 存储注意事项.

数据访问模式。通过这个我了解了表的查询和更新方式。请记住,聚集键决定表中行的实际顺序。对于某些访问模式,某些布局在查询速度或更新并发性方面具有很大的不同:

  • 当前数据与存档数据。在许多应用中,属于当前月份的数据被频繁访问,而过去的数据则很少被访问。在这种情况下,表设计使用表分区按交易日期,通常使用滑动窗口算法。当月分区保留在位于热快速磁盘的文件组上,存档的旧数据被移动到托管在更便宜但速度较慢的存储上的文件组。显然,在这种情况下,聚集键(日期)不是主键(事务 ID)。两者的分离是由规模要求驱动的,因为查询优化器将能够检测到查询只对当前分区感兴趣,甚至不查看历史分区。

  • 先进先出队列式处理。在这种情况下,表有两个热点:发生插入的尾部(入队)和发生删除的头部(出队)。聚集键必须考虑到这一点并组织表以物理分离磁盘上的尾部和头部位置,以便允许入队和出队之间的并发性,例如。通过使用排队顺序键。在pure队列中此聚集键是唯一的键,因为表上没有主键(它包含messages, not entities)。但大多数时候队列并不是纯粹的,它还充当实体的存储,以及实体之间的线路queuetable是模糊的。在这种情况下,还有一个主键,它不能是聚集键:实体可以重新排队,从而更改排队顺序聚集键值,但它们不能更改主键值。未能看到分离是用户表支持的队列如此难以正确处理并充满死锁的主要原因:因为入队和出队是在表中交错发生的,而不是集中在队列的尾部和头部。

  • 相关处理。当应用程序设计良好时,它将在其工作线程之间划分相关项目的处理。例如,处理器被设计为具有 8 个工作线程(假设与服务器上的 8 个 CPU 相匹配),因此处理器会在它们之间对数据进行分区,例如。工作人员 1 仅选取名为 A 到 E 的帐户,工作人员 2 F 到 J 等。在这种情况下,表实际上应按帐户名称(或最左边位置是帐户名称的第一个字母的复合键)进行集群,以便工作人员在表中本地化他们的查询和更新。这样的表将有 8 个不同的热点,围绕每个工作人员当前集中的区域,但重要的是它们不重叠(无阻塞)。这种设计在高吞吐量 OLTP 设计和 TPCC 基准测试负载中很普遍,其中这种分区也反映在缓冲池中加载的页面的内存位置(NUMA 局部性),但我离题了。

存储注意事项。聚集键width对表的存储有巨大的影响。对于一个键来说,它占用了 B 树的每个非叶页中的空间,因此较大的键将占用更多的空间。其次,通常更重要的是,聚集键被每个非聚集键用作查找键,因此every非聚集键必须存储每行的聚集键的完整宽度。这就是像 varchar(256) 和 guid 这样的大型聚集键成为聚集索引键的糟糕选择的原因。
此外,键的选择也会影响聚集索引碎片,有时会极大地影响性能。

这两种力量有时可能是对立的,数据访问模式需要某个大的聚集键,这会导致存储问题。在这种情况下,当然需要平衡,但没有神奇的公式。您进行测量和测试以达到最佳状态。

那么我们能从这一切中得到什么呢?始终首先考虑聚集键,它也是表单的主键entity_id IDENTITY(1,1) NOT NULL。将两者分开并在适当时相应地组织表(例如按日期分区)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我应该设计一个主键为 varchar 还是 int 的表? 的相关文章

  • 时间历史表中的重复项

    We have JCC提供从中抽取数据的Oracle to SQL Server 2016 由于某些未知原因 历史表中存在具有相同开始和结束时间的重复项 怎么会发生呢 我尝试根据条件更新记录SET Column Column 在这种情况下
  • 如何连接mysql表

    我有一张这样的旧桌子 user gt id name address comments 现在我必须创建一个 别名 表 以允许某些用户出于某种原因拥有别名 我创建了一个新表 user alias 如下所示 user alias gt name
  • 该模型已具有同名的元素 - ASP.NET

    我正在使用 ASP Net Web 应用程序 每当我尝试添加FOREIGN KEY此错误出现在数据工具操作中 SQL71508 该模型已具有同名的元素 dbo FK Sellers Users SQL71508 该模型已经有一个元素 具有相
  • SQL Server 表不使用默认值

    我正在使用 SSIS 包填充表 这个想法是 每当包上传到表时 它都会使用时间戳记该值getdate 当我打开它时 我的 DDL 看起来像这样 CREATE TABLE REPORTING post ssis table 1 validati
  • 无法将参数值从 TimeSpan 转换为 DateTime

    我正在使用 SQL Server 2008 首先我给了SqlDbType Time for System TimeSpan插入和更新的参数类型 我工作成功 现在我改为DbType Time代替SqlDbType Time 这给了我错误消息
  • 如何在asp.net中基于teamviewerid启动teamviewer会话

    我有一个来自 SQL 表的计算机列表Computers 有列computerid guid computername varchar 80 TeamviewerID varchar 30 我想创建一个链接 teamviewer id 并可以
  • 长 IN 子句是代码异味吗?

    简单的问题 想知道长 IN 子句是否有代码味道 我真的不知道如何证明它的合理性 除了我认为的味道之外 我无法解释为什么它有味道 select name code capital population flower bird from us
  • Oracle SQL - 如何使用 RANK() 或 DENSE_RANK() 和 ROW_NUMBER() 分析函数获取不同的行?

    我希望获得每个部门前 3 名不同的薪资 我能够使用RANK or DENSE RANK or ROW NUMBER 但我的表有一些工资相同的记录 下面提到的是我的查询及其结果 20部薪资前三名应该是6000 3000 2975 但是有 2
  • SQL 内连接两个具有相同列名的表

    我有两个表 其列数不同 我不知道有多少列或名称是什么 例如表 A 和表 B TableA ID B ID variable TableB ID variable Query SELECT TableA TableB FROM TableA
  • SQL 网络接口,错误:50 - 发生本地数据库运行时错误。无法创建自动实例

    我正在尝试构建一个 ASP NET MVC 5 Web 应用程序 它具有MyDatabase mdf文件在App Data文件夹 我安装了 SQL Server 2014 ExpressLocalDb实例 我可以使用服务器资源管理器编辑数据
  • SQL Server:使用计算列批量插入表

    我尝试使用 bcp 将文本文件中的数据插入到具有计算列的 SQL Server 2016 表中 我的 bcp 命令 bcp Test dbo myFirstImport IN D myFirstImport txt f D myFirstI
  • 为什么从 SQL Server 2000 升级到 2005 会导致查询速度变慢?

    将数据库从 SQL Server 2000 升级到 SQL Server 2005 会导致查询速度变慢 是否有任何常见原因 这是来自具有数百个表的 ASP NET 1 1 应用程序 所有内容都已索引 并且似乎在旧版本上运行良好 升级后 您需
  • 在 SQLAlchemy 中选择 NULL 值

    这是我的 PostgreSQL 表 test gt create table people name varchar primary key marriage status varchar test gt insert into peopl
  • 如何解决将表达式转换为数据类型 int 时出现算术溢出错误?

    我有以下查询 CTE to remove outliers e g remove the fastest and slowest results WITH MinMaxCTE AS SELECT ServerName CONVERT VAR
  • 实体框架 - 悲观锁定

    我想做的基本上是NHibernate 做什么 http knol google com k nhibernate chapter 10 transactions and concurrency 10 282E 296 282E 29 28C
  • 数据库设计 - 何时拆分表?

    有时创建一个单独的表会产生更多工作 我是否应该将其拆分 例如 在我的项目中 我有一张客户表 每个客户对每种产品都有自己的特殊价格 只有5种产品 未来不会计划更多产品 每个客户也有一周中公司向他交付产品的独特日子 当日期和产品价格是客户表中的
  • CLR 程序集不会在 64 位 SQL Server 2005 中加载

    我们在安装 SQL Server 2005 32 位 时使用带有一些用户定义函数的程序集 我们使用如下脚本将其部署到生产环境 CREATE ASSEMBLY Ourfunctions AUTHORIZATION dbo FROM 0x4D5
  • 检查SQL Server数据库表中是否存在表或列

    在 SQL Server 数据库中创建列或表之前 我想检查所需的表和 或列是否存在 我已经四处搜寻 到目前为止发现了两种方法 我不想使用存储过程 通过使用SqlCommand ExecuteScalar 方法并捕获异常来确定表 列是否存在
  • 在每个条目一分钟内通过联系人查找 20 个或更多条目

    我们正在收集联系人及其访问的每个页面的一些分析数据 许多分析数据来自恶意攻击或机器人 因此它们在一分钟之内就访问了网站的 20 多个页面 我希望能够每天清除一次这些数据 但不知道如何编写一个 SQL 查询来选择该联系人在一分钟内访问超过 2
  • CROSS APPLY WHERE 子句在交叉应用之前或结果之后起作用吗

    我正在做一种我们在一个内部应用程序中需要的自定义模糊匹配算法 我正在努力加快速度 当我对模糊函数进行交叉应用以查找建议的匹配项时 我不想搜索不必要的数据 这是函数 select top 5 Manufacturer Manufacturer

随机推荐

  • 如何向socket通道写入数据

    是否有任何小型工作程序可以使用 java nio 从客户端接收数据并向客户端发送数据 实际上我无法写入套接字通道 但我能够读取传入的数据 如何向socket通道写入数据 谢谢 迪帕克 您可以将数据写入套接字通道 如下所示 import ja
  • 固定位置的div

    我有一个样式为position fixed 的div 我希望它向下滚动页面 但我不希望div 溢出到页脚中 我怎样才能做到这一点 提前致谢 肖恩 尝试这个 CSS body html height 100 margin 0 padding
  • jQuery 事件按键:按下了哪个键? A-Z,&@

    在 keydown 上我从 jQuery 得到以下信息 jQuery Event altKey false attrChange undefined attrName undefined bubbles true button undefi
  • Win 7 和 Win 8 中最大化时的无边界应用程序隐藏在任务栏后面

    我在 WPF 中创建了一个无边框窗口 我编写了一个事件来最大化窗口 但在最大化时 窗口的一部分有时隐藏在任务栏后面 片刻后出现在任务栏顶部 如何确保窗口每次都保持在任务栏的顶部 以下是我实施的方法 private void OnMaximi
  • Python WindowsError: [Error 3] 尝试重命名时系统找不到指定的文件

    我不明白出了什么问题 我以前使用过重命名没有任何问题 并且在其他类似问题中找不到解决方案 import os import random directory C whatever string alphabet abcdefghijklmn
  • 使用会话存储变量

    我有一个在每次换页时都会更新的变量 但我想以某种方式将值存储在第一次调用中 变量是例如 sizeOfSearch value HotelList activePropertyCount 第一次加载页面时 它是 933 在下一页上检索到相同的
  • Dataproc:配置 Spark 驱动程序和执行程序 log4j 属性

    正如前面的答案中所解释的 更改 Spark 集群的详细程度的理想方法是更改对应的log4j properties 但是 在dataproc上 Spark在Yarn上运行 因此我们必须调整全局配置而不是 usr lib spark conf
  • $.param() 生成的查询字符串包含数组的方括号

    我有一个这样的对象 var queryObject name Shwetanka subjects Mathematics Physics Computers stream science 当我使用此创建查询字符串时 param query
  • Spark 从不同模式目录读取数据帧

    我的spark程序必须从一个目录中读取 该目录有不同模式的数据 目录 子目录1 文件1 10 外星人1 11 鲍勃 目录 子目录2 文件2 蓝色 123 芝加哥2 红色 34 达拉斯 大约 50 个具有不同模式的目录 我的 Spark 作业
  • Django 上传图像 - 从表单到 Rackspace/S3,无需任何操作

    我只想使用表单上传图像 JPG 然后将该图像发送到 Rackspace Cloud Files 或 Amazon S3 没有操作该文件 无需保存到磁盘 一切都保存到内存 托管在云服务器上 图片大小不会超过75kb Update 两个注意事项
  • 将变量值传递给锚标记中的 href 参数

    如何将变量值传递给锚标记中的 href 参数 a something here a 我希望锚标记在执行上述代码后看起来像这样 a href http www google com jobid 10 something here a 但不知何
  • 查找并替换对象数组中的部分属性值

    我需要在对象数组中搜索关键字并替换它的所有实例 例如 我有以下数组 const test marketType 90 displayName FT Total Match scoreType Over Under 0 75 Remove m
  • 在WPF中检测鼠标直接越过边框

    我有一个简单的 UserControl 其直接子元素是边框
  • 计算字符串中特定的相同字符的连续出现次数 - PHP

    我正在尝试计算一些 连胜 特别是连续获胜和失败的最高次数 以及大多数没有获胜的比赛 没有失败的比赛的发生次数 我有一个看起来像这样的字符串 WWWDDWWWWLLWLLLL 为此我需要能够返回 A 字符的最长连续运行 然后我将复制 L 没有
  • 从文件中读取并查找特定行

    我需要根据某些关键字获取设置文件中的信息 我无法更改格式 该文件是这样的 username myusername address 156a1355e3486f4 data function i if i 0 return true else
  • 使用 Google Translate API 将 JavaScript 内容翻译为 HTML

    我需要创建一个按钮 能够在法语和英语之间切换页面内容的语言 我如何使用 Google Translate API 来实现此目的 这有帮助吗 div div
  • 如何限制上传图片的宽度或高度

    我想以类似的方式操作 调整图像大小兴趣但我不确定解决这个问题的最佳方法是什么 目标是允许混合纵向和横向图像 但对最大高度和宽度施加一些限制 我看到的问题是 如果我调整宽度 肖像图像可能会变得太薄 而风景图像则相反 关于如何使用 PHP 实现
  • 重构 JSON

    我现在有来自服务器的 JSON 响应 但我想根据日期重组它 例如我现在有 items A name a date 2 10 2010 sales 100 name b date 6 10 2010 sales 400
  • “git分支”和“git checkout -b”有什么区别?

    I used git checkout b创建一个新分支 我觉得git branch做同样的事情 如果这两个命令有不同的话 它们有何不同 git checkout b BRANCH NAME创建一个新分支并签出新分支 同时git branc
  • 我应该设计一个主键为 varchar 还是 int 的表?

    我知道这是主观的 但我想了解人们的意见 并希望在设计 sql server 表结构时可以应用一些最佳实践 我个人认为 在固定 最大 长度的 varchar 上键入表是不行的 因为这意味着必须在使用它作为外键的任何其他表上传播相同的固定长度