与关系型数据库打交道的我们皆知(或正在学习)SQL的独特性。要达到所需结果且高效地做到这一点,需要进行一项繁琐的过程,其中一部分特点是学习不熟悉的范例,并发现我们最熟悉的一些编程模式在此处不起作用。您见过哪些常见反模式(或者自己犯了哪些)?
与关系型数据库打交道的我们皆知(或正在学习)SQL的独特性。要达到所需结果且高效地做到这一点,需要进行一项繁琐的过程,其中一部分特点是学习不熟悉的范例,并发现我们最熟悉的一些编程模式在此处不起作用。您见过哪些常见反模式(或者自己犯了哪些)?
大多数程序员倾向于将其UI逻辑混合在数据访问层中,这一点一直让我感到失望。
SELECT
FirstName + ' ' + LastName as "Full Name",
case UserRole
when 2 then "Admin"
when 1 then "Moderator"
else "User"
end as "User's Role",
case SignedIn
when 0 then "Logged in"
else "Logged out"
end as "User signed in?",
Convert(varchar(100), LastSignOn, 101) as "Last Sign On",
DateDiff('d', LastSignOn, getDate()) as "Days since last sign on",
AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' +
City + ', ' + State + ' ' + Zip as "Address",
'XXX-XX-' + Substring(
Convert(varchar(9), SSN), 6, 4) as "Social Security #"
FROM Users
通常,程序员这样做是因为他们打算将其数据集直接绑定到网格中,而在服务器端格式化SQL Server比在客户端上格式化更方便。
像上面所示的查询非常脆弱,因为它们紧密耦合了数据层和 UI 层。除此之外,这种编程风格彻底防止了存储过程的可重用性。
以下是我的前三:
第一。未指定字段列表。(编辑说明:为了避免混淆:这是一个生产代码规则。它不适用于一次性分析脚本 - 除非我是作者。)
SELECT *
Insert Into blah SELECT *
应该是这样的
SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist
第二种方法是使用游标和while循环,当需要使用循环变量的while循环时。
DECLARE @LoopVar int
SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable)
WHILE @LoopVar is not null
BEGIN
-- Do Stuff with current value of @LoopVar
...
--Ok, done, now get the next value
SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable
WHERE @LoopVar < TheKey)
END
第三个。通过字符串类型实现日期逻辑。
--Trim the time
Convert(Convert(theDate, varchar(10), 121), datetime)
应该是这样的
--Trim the time
DateAdd(dd, DateDiff(dd, 0, theDate), 0)
最近我看到了“一个查询优于两个,是吧?”这句话的频繁出现。SELECT *
FROM blah
WHERE (blah.Name = @name OR @name is null)
AND (blah.Purpose = @Purpose OR @Purpose is null)
这个查询需要根据参数值生成两到三个不同的执行计划。只有一个执行计划被生成并保留在缓存中,用于此SQL文本。无论参数值如何,都将使用该计划。这导致间歇性的性能下降。最好编写两个查询(每个查询对应一个预期的执行计划)。
易于人类阅读的密码字段,不用解释。
对索引列使用LIKE操作符,我几乎想说一般都可以使用LIKE。
重复使用SQL生成的主键值。
令人惊讶的是还没有人提到神表。没有任何东西比拥有100个位标记、大字符串和整数的列更能说明“生命力”了。
然后还有“我想念.ini文件”模式:将CSV文件、竖线分隔字符串或其他需要解析的数据存储在大型文本字段中。
对于MS SQL Server来说,完全不需要使用游标。使用其他方法可以完成游标任务。
LIKE '%LIKE'
。 - Johan不必深入挖掘:不使用预处理语句。
from employee t1,
department t2,
job t3,
...
使阅读一条大型的SQL语句变得比必要的困难。
我的恼人之处是由总经理最好朋友的狗美容师的8岁儿子组成的450列Access表和不正常化数据结构导致存在的可疑查找表。
通常情况下,这种查找表看起来像这样:
ID INT, 名称 NVARCHAR(132), IntValue1 INT, IntValue2 INT, CharValue1 NVARCHAR(255), CharValue2 NVARCHAR(255), Date1 DATETIME, Date2 DATETIME
我已经失去了统计使用这种丑陋数据结构系统的客户数量。
在创建表、存储过程等时使用空格。我可以接受驼峰命名法或下划线,单数或复数,大写或小写,但是如果需要引用一个带有空格的表或列,特别是如果它们之间的空格很奇怪(是的,我遇到过这种情况),那真的会让我很恼火。
非规范化的数据。一张表不必完全规范化,但当我遇到一个员工信息表中包含当前评估得分或他们的主要任何事项时,这告诉我我可能需要在某个时候创建一个单独的表,然后尝试保持它们同步。我会先规范化数据,然后如果看到非规范化可以提高效率的地方,我才会考虑使用。
过度使用视图或游标。视图有其作用,但当每张表都被包装在一个视图中时就太多了。我有时候需要使用游标,但通常你可以使用其他机制来完成。
Access。程序可以成为反模式吗?我们公司使用的是SQL Server,但有些人会因为Access易于获取、"易于使用"和对非技术用户的"友好性"而使用它。这里有太多需要讲解的,但如果你处于类似的环境中,你就知道。
存储时间值时,只应该使用UTC时区,不应该使用本地时间。
使用SP作为存储过程名称的前缀,这是因为它会首先在系统存储过程位置中搜索,而不是自定义位置。