mysql - 有没有理由担心表中的列顺序?
我知道你可以用FIRST和AFTER改变MySQL中的列顺序,但为什么你要打扰? 由于好的查询在插入数据时明确地命名列,是否真的有理由关心列中的列的顺序?
13个解决方案
83 votes
列顺序对我调整过的一些数据库有很大的性能影响,包括Sql Server,Oracle和MySQL。 这篇文章有很好的经验法则:
首先是主键列
接下来是外键列。
接下来经常搜索的列
以后经常更新的列
Nullable列最后。
在更频繁使用的可空列之后最少使用可空列
性能差异的一个示例是索引查找。 数据库引擎根据索引中的某些条件查找行,并返回行地址。 现在说你正在寻找SomeValue,它在这个表中:
SomeId int,
SomeString varchar(100),
SomeValue int
引擎必须猜测SomeValue的起始位置,因为SomeString的长度未知。 但是,如果您将订单更改为:
SomeId int,
SomeValue int,
SomeString varchar(100)
现在引擎知道在行开始后可以找到SomeValue 4个字节。 因此,列顺序可能会产生相当大的性能影响。
编辑:Sql Server 2005在行的开头存储固定长度的字段。 每行都有一个varchar开头的引用。 这完全否定了我上面列出的效果。 因此,对于最近的数据库,列顺序不再有任何影响。
Andomar answered 2019-06-12T05:35:13Z
37 votes
更新:
在MySQL中,可能有理由这样做。
由于可变数据类型(如@Andomar)在Oracle中以可变长度存储,因此数据库引擎应遍历每行中的所有先前列以查找给定数据的偏移量。
对于@Andomar列,影响可能高达17%。
有关详细信息,请参阅我的博客中的此条目:
选择列顺序
在@Andomar中,尾随Oracle列不占用空间,这就是为什么您应该始终将它们放在表的末尾。
同样在@Andomar和Oracle中,在大行的情况下,可能出现ROW CHAINING。
@Andomar正在拆分不适合一个块的行,并将其跨越多个块,并与链接列表连接。
读取不适合第一个块的尾随列将需要遍历链表,这将导致额外的@Andomar操作。
有关@Andomar的详细说明,请参见本页Oracle:
这就是为什么你应该将经常使用的列放在表的开头,将经常不使用的列或者通常为@Andomar的列放到表的末尾。
重要的提示:
如果你喜欢这个答案,并想投票支持,请投票给@Andomar的答案。
他回答了同样的事情,但似乎无缘无故地被投票。
Quassnoi answered 2019-06-12T05:37:10Z
6 votes
在上一次工作的Oracle培训期间,我们的DBA建议将所有非可空列放在可空的列之前是有利的......尽管TBH我不记得原因的细节。 或者也许只是那些可能会更新的应该到最后? (如果扩展,可能会推迟行)
一般来说,它不应该有任何区别。 正如您所说,查询应始终指定列本身,而不是依赖于“select *”的排序。 我不知道有任何DB允许它们被更改......好吧,我不知道MySQL允许它直到你提到它。
araqnid answered 2019-06-12T05:37:44Z
5 votes
一些写得不好的应用程序可能依赖于列顺序/索引而不是列名。 他们不应该,但确实发生了。 更改列的顺序会破坏此类应用程序。
Craig Walker answered 2019-06-12T05:38:10Z
4 votes
输入时输出的可读性:
select * from
在您的数据库管理软件?
这是一个非常虚假的原因,但此刻我无法想到其他任何事情。
ChrisF answered 2019-06-12T05:38:50Z
4 votes
不,SQL数据库表中列的顺序完全不相关 - 除了显示/打印目的。 重新排序列没有意义 - 大多数系统甚至没有提供这样做的方法(除了删除旧表并使用新的列顺序重新创建它)。
渣
编辑:从关系数据库的维基百科条目,这里的相关部分,我清楚地表明,列顺序永远不应该是关注:
关系被定义为一组n元组。 在数学和关系数据库模型中,集合是一个无序的项集合,尽管有些DBMS对其数据强加了一个顺序。 在数学中,元组有一个顺序,并允许重复。 E.F. Codd最初使用这个数学定义来定义元组。 后来,这是E.F. Codd的一个很好的见解,即在基于关系的计算机语言中使用属性名称而不是排序将更加方便(通常)。 这种洞察力至今仍在使用。
marc_s answered 2019-06-12T05:39:33Z
2 votes
我能想到的唯一原因是调试和消防。 我们有一个表,其“名称”列出现在列表的第10位。 当您从(1,2,3)中的id执行快速select *表时,这是一个痛苦,然后您必须滚动查看名称。
但那是关于它的。
Chris Simpson answered 2019-06-12T05:40:06Z
1 votes
通常情况下,最大的因素是下一个必须在系统上工作的人。 我尝试先将主键列,第二个外键列,然后按重要性/重要性的降序排列其余列。
James L answered 2019-06-12T05:40:32Z
1 votes
除了显而易见的性能调优之外,我只是碰到了一个角落案例,其中重新排序列导致(以前正常运行的)sql脚本失败。
从文档“TIMESTAMP和DATETIME列没有自动属性,除非明确指定它们,但有以下例外:默认情况下,如果两者都没有明确指定,则第一个TIMESTAMP列同时具有DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP”[https:// dev。mysql.com/doc/refman/5.6/en/timestamp-initialization.html]
因此,如果该字段是表中的第一个时间戳(或日期时间),则命令ALTER TABLE table_name MODIFY field_name timestamp(6) NOT NULL;将起作用,但不起作用。
显然,您可以更正alter命令以包含默认值,但是由于列重新排序而导致工作停止工作的查询这一事实让我头疼。
slacker525600 answered 2019-06-12T05:41:21Z
0 votes
您唯一需要担心列顺序的是您的软件是否特别依赖于该订单。 通常这是因为开发人员变得懒惰并且做了select *,然后通过索引而不是结果中的名称来引用列。
Soviut answered 2019-06-12T05:41:48Z
0 votes
如果您将要使用UNION,那么如果您有关于其排序的约定,它会使匹配列更容易。
Allain Lalonde answered 2019-06-12T05:42:14Z
0 votes
通常,当您通过Management Studio更改列顺序时,SQL Server中发生的情况是它使用新结构创建临时表,将数据从旧表移动到该结构,删除旧表并重命名新表。 正如您可能想象的那样,如果您有一个大表,这对性能来说是一个非常糟糕的选择。 我不知道My SQL是否也这样做,但这也是我们许多人避免重新排序列的原因之一。 由于select *永远不应该在生产系统中使用,因此在最终添加列对于设计良好的系统来说并不是问题。 表中的列顺序应该在genral中不被混淆。
HLGEM answered 2019-06-12T05:42:42Z
0 votes
如上所述,存在许多潜在的性能问题。 我曾经在一个数据库上工作,如果你没有在查询中引用那些列,那么最后放置非常大的列可以提高性能。 显然,如果记录跨越多个磁盘块,数据库引擎可能会在获得所需的所有列后停止读取块。
当然,任何性能影响都高度依赖于您正在使用的制造商,但也可能依赖于该版本。 几个月前,我注意到我们的Postgres无法使用索引进行“喜欢”比较。 也就是说,如果你写了“somecolumn like'M%'”,那么当它找到第一个N时,跳过M并退出是不够聪明的。我打算改变一堆查询以使用“之间”。 然后我们得到了Postgres的新版本,它智能地处理了类似的东西。 很高兴我从来没有改变查询。 显然这里并不直接相关,但我的观点是,为了提高效率而做的任何事情都可能在下一个版本中过时。
列顺序几乎总是与我非常相关,因为我经常编写通用代码来读取数据库模式以创建屏幕。就像,我的“编辑记录”屏幕几乎总是通过阅读模式来获取字段列表,然后按顺序显示它们。如果我更改了列的顺序,我的程序仍然可以工作,但显示可能对用户来说很奇怪。比如,你希望看到名字/地址/城市/州/邮编,而不是城市/地址/邮编/名称/州。当然,我可以将列的显示顺序放在代码或控制文件中,但是每次添加或删除列时我们都必须记住更新控制文件。我喜欢说一次话。此外,当编辑屏幕完全由架构构建时,添加新表可能意味着编写零行代码来为其创建编辑屏幕,这很酷。 (好吧,好吧,在实践中通常我必须在菜单中添加一个条目来调用通用编辑程序,而且我一般都放弃了通用“选择要更新的记录”,因为有太多的例外使它变得实用。)
Jay answered 2019-06-12T05:43:27Z