Sql 使用连接来避免数字ID是件坏事吗?

Sql 使用连接来避免数字ID是件坏事吗?,sql,oracle,join,Sql,Oracle,Join,昨天我看到了这样的问题: SELECT <some fields> FROM Thing WHERE thing_type_id = 4 所以我开始在一两个查询中使用它,我的同事很快发现了我:“嘿,你在查询中有文字代码!”,嗯,你知道,我们通常使用pks来实现这一点。” 虽然我可以理解这种方法不是通常的方法(嘿,直到现在我也不这样),但它真的那么糟糕吗 这样做的利弊是什么?我的主要目标是可读性,但我担心性能,我想确认这个想法是否合理 EDIT:请注意,我不是在谈论PL/SQL,而是

昨天我看到了这样的问题:

SELECT <some fields>
FROM Thing
WHERE thing_type_id = 4
所以我开始在一两个查询中使用它,我的同事很快发现了我:“嘿,你在查询中有文字代码!”,嗯,你知道,我们通常使用pks来实现这一点。”

虽然我可以理解这种方法不是通常的方法(嘿,直到现在我也不这样),但它真的那么糟糕吗

这样做的利弊是什么?我的主要目标是可读性,但我担心性能,我想确认这个想法是否合理

EDIT:请注意,我不是在谈论PL/SQL,而是直接查询,这种查询通常以SELECT开头。

编辑2: 为了进一步澄清我的情况,我举了一些虚假(但结构相似)的例子,下面是我的表格:

Thing
------------------------------------------
thing_id | <attributes...> | thing_type_id
    1                              3
    4                              7
    5                              3

ThingType
--------------------------------------------------
thing_type_id | thing_type_code | <attributes...>
       3           'TYPE_C'         
       5           'TYPE_E'
       7           'TYPE_G'
东西
------------------------------------------
物品|标识|物品|类型|标识
1                              3
4                              7
5                              3
事物类型
--------------------------------------------------
物品类型标识物品类型代码
3“C型”
5‘E型’
7'类型_G'
thing_type_代码和thing_type_id一样唯一。它目前也被用作显示字符串,我认为这是一个错误,但可以通过添加一个thing_type_标签字段来轻松修复,该字段现在复制thing_type_代码,如果需要,以后可以随时更改


假设,使用thing\u type\u code='type\u C'进行过滤,我肯定会得到一行,恰好是thing\u type\u id=3。连接仍然可以(而且很可能应该)使用数字ID完成。

在SQL查询中,您肯定会对连接带来性能影响(实际上,在SQL server中发生了多个查询)。问题在于,对性能的影响是否足以抵消这些好处

如果这只是一个可读性问题,那么您可能更愿意追求更好的性能并避免连接,但我建议您考虑潜在的完整性问题(例如,如果示例中的类型值4被后续的另一个进程更改,则会发生什么情况-整个应用程序可能会失败)


如果这些值永远不会改变,那么就使用PKs——这是开发人员的决定——没有规则。一个选项可能最适合一个查询,而不适合另一个查询。

我假设问题是关于两个版本的查询——一个是数字比较,另一个是连接和字符串比较

您的同事是正确的,带有
where thing\u id in(id列表)
的表单将比
join
的表单性能更好。但是,如果
thing\u id
没有索引,性能上的差异可能非常小。查询已经需要对原始表进行完整的表扫描

在大多数其他方面,使用
join
的版本更好。特别是,它使查询的意图更清晰,并且总体上使查询更易于维护。对于一个小的参考表,性能影响可能不明显。事实上,在某些数据库中,这种形式可能更快。当中的
作为一系列
表达式计算时,会发生这种情况。如果列表很长,执行索引查找可能会更快


join
方法有一个缺点。如果列中的值发生更改,则还需要更改代码。如果建议使用主键的同事有过这样的经历,我也不会感到惊讶。他/她正在开发一个应用程序,并使用
join
S构建它。伟大的很多代码。一切正常。都是可维护的。然后每周,用户决定更改代码的定义。这会使几乎任何理智的人都更喜欢主键而不是使用参考表。

主键值应该而不是在查询中编码为文本

原因是:

  • 关系理论认为PKs不应该传达任何意义。甚至没有一个具体的身份。它们应该是严格的行标识符,而不是依赖于特定的值
  • 由于操作上的原因,PK在不同的环境(如开发、qa和产品)中通常是不同的,甚至对于“查找”表也是如此
由于这些原因,在查询中编码文字ID是脆弱的


将数据文本编码为
'OPENED'
'ONHOLD'
是一种很好的做法,因为这些值在所有服务器和环境中都是一致的。如果它们确实发生更改,则将查询更改为同步将成为更改脚本的一部分。

请参阅标记注释。我想你们没事,但我可以就此事给你们2美分。 如果该值在一个查询的范围内,我想这样写:

declare HOLD int = 4

SELECT <some fields>
FROM Thing
WHERE thing_type_id = HOLD
这样,我就可以将selects上的类型重新用作枚举器

declare TYPE int
set TYPE = (select id from ThingType where description = 'HOLD')

SELECT <some fields>
FROM Thing
WHERE thing_type_id = TYPE
声明类型int
设置类型=(从ThingType中选择id,其中描述='HOLD')
挑选
从事物
其中thing\u type\u id=type
这样我就保持了意义和性能(还可以在域值上强制执行关系完整性)


此外,我可以在应用程序级别使用枚举器,并将数值传递给查询。快速浏览一下该枚举器,我会给出该数字的含义。

对于PL/SQL,在包中定义常量是有意义的,例如

DECLARE
   C_OPENED CONSTANT NUMBER := 3;
   C_ONHOLD CONSTANT NUMBER := 4;
BEGIN
SELECT <some fields>
INTO ...
FROM Thing
WHERE thing_type_id in (C_OPENED, C_ONHOLD);
END;
声明
C_开启常数:=3;
C_保持不变数:=4;
开始
挑选
进入
从事物
事物类型id所在的位置(C_打开,C_保持);
结束;

有时,在定义所有常用常量的地方创建全局包(没有主体)是很有用的。如果文字发生变化,您只需在单个位置修改常量定义。

连接使用主键您的同事说的“我们通常使用pks”是什么意思
declare TYPE int
set TYPE = (select id from ThingType where description = 'HOLD')

SELECT <some fields>
FROM Thing
WHERE thing_type_id = TYPE
DECLARE
   C_OPENED CONSTANT NUMBER := 3;
   C_ONHOLD CONSTANT NUMBER := 4;
BEGIN
SELECT <some fields>
INTO ...
FROM Thing
WHERE thing_type_id in (C_OPENED, C_ONHOLD);
END;