我们所有使用关系数据库的人都知道(或正在学习)SQL是不同的。获得期望的结果,并有效地这样做,涉及到一个乏味的过程,其部分特征是学习不熟悉的范例,并发现一些我们最熟悉的编程模式在这里不起作用。常见的反模式是什么?


当前回答

以下是我的前3名。

1号。指定字段列表失败。(编辑:为了防止混淆:这是一个生产代码规则。它不适用于一次性分析脚本——除非我是作者。)

SELECT *
Insert Into blah SELECT *

应该是

SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist

2号。使用游标和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

3号。DateLogic通过字符串类型。

--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文本,只生成一个执行计划并保存在缓存中。无论参数的值是多少,都将使用该计划。这会导致间歇性的性能不佳。最好编写两个查询(每个预期的执行计划一个查询)。

其他回答

临时表滥用。

特别是这类事情:

SELECT personid, firstname, lastname, age
INTO #tmpPeople
FROM People
WHERE lastname like 's%'

DELETE FROM #tmpPeople
WHERE firstname = 'John'

DELETE FROM #tmpPeople
WHERE firstname = 'Jon'

DELETE FROM #tmpPeople
WHERE age > 35

UPDATE People
SET firstname = 'Fred'
WHERE personid IN (SELECT personid from #tmpPeople)

不要从查询中构建临时表,只是为了删除不需要的行。

是的,我在生产db中看到过这种形式的代码页。

以下是我的前3名。

1号。指定字段列表失败。(编辑:为了防止混淆:这是一个生产代码规则。它不适用于一次性分析脚本——除非我是作者。)

SELECT *
Insert Into blah SELECT *

应该是

SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist

2号。使用游标和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

3号。DateLogic通过字符串类型。

--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文本,只生成一个执行计划并保存在缓存中。无论参数的值是多少,都将使用该计划。这会导致间歇性的性能不佳。最好编写两个查询(每个预期的执行计划一个查询)。

反向观点:过度痴迷于正常化。

大多数SQL/ rbdb系统提供了许多非常有用的特性(事务、复制),即使对于非标准化的数据也是如此。磁盘空间很便宜,有时操作/过滤/搜索获取的数据比编写1NF模式更简单(更容易的代码,更快的开发时间),并处理其中的所有麻烦(复杂的连接,讨厌的子选择等)。

我发现过度标准化的系统通常是不成熟的优化,特别是在开发的早期阶段。

(再想想……http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/)

也许这不是一个反模式,但它惹恼了我,当某些数据库的DBA(好吧,我在这里说的是Oracle)用Oracle风格和代码约定编写SQL Server代码,当它运行如此糟糕时抱怨。受够了游标Oracle的人!SQL是基于设置的。

select some_column, ...
from some_table
group by some_column

假设结果将按some_column排序。我在Sybase上看到过这种情况,其中假设成立(目前)。