我们所有使用关系数据库的人都知道(或正在学习)SQL是不同的。获得期望的结果,并有效地这样做,涉及到一个乏味的过程,其部分特征是学习不熟悉的范例,并发现一些我们最熟悉的编程模式在这里不起作用。常见的反模式是什么?
当前回答
没有使用With子句或适当的连接并依赖子查询。
反模式:
select
...
from data
where RECORD.STATE IN (
SELECT STATEID
FROM STATE
WHERE NAME IN
('Published to test',
'Approved for public',
'Published to public',
'Archived'
))
好: 我喜欢使用with子句使我的意图更易于阅读。
with valid_states as (
SELECT STATEID
FROM STATE
WHERE NAME IN
('Published to test',
'Approved for public',
'Published to public',
'Archived'
)
select ... from data, valid_states
where data.state = valid_states.state
最好的:
select
...
from data join states using (state)
where
states.state in ('Published to test',
'Approved for public',
'Published to public',
'Archived'
)
其他回答
应用程序连接 不仅仅是一个SQL问题,而是在寻找问题的描述和发现这个问题时,我很惊讶它没有被列出。
正如我所听到的那样,应用程序连接是指从两个或多个表中取出一组行,然后用一对嵌套的for循环将它们连接到(Java)代码中。这给系统(应用程序和数据库)带来了负担,必须识别整个叉乘,检索它并将其发送给应用程序。假设应用程序可以像数据库一样快地过滤叉乘(不确定),只是更快地削减结果集意味着更少的数据传输。
没有注释的存储过程或函数…
使用SQL作为美化的ISAM(索引顺序访问方法)包。特别是嵌套游标,而不是将SQL语句组合成一个更大的语句。这也算“滥用优化器”,因为实际上优化器能做的不多。这可以与非准备语句结合使用,以获得最大的效率:
DECLARE c1 CURSOR FOR SELECT Col1, Col2, Col3 FROM Table1
FOREACH c1 INTO a.col1, a.col2, a.col3
DECLARE c2 CURSOR FOR
SELECT Item1, Item2, Item3
FROM Table2
WHERE Table2.Item1 = a.col2
FOREACH c2 INTO b.item1, b.item2, b.item3
...process data from records a and b...
END FOREACH
END FOREACH
正确的解决方案(几乎总是)是将两个SELECT语句合并为一个:
DECLARE c1 CURSOR FOR
SELECT Col1, Col2, Col3, Item1, Item2, Item3
FROM Table1, Table2
WHERE Table2.Item1 = Table1.Col2
-- ORDER BY Table1.Col1, Table2.Item1
FOREACH c1 INTO a.col1, a.col2, a.col3, b.item1, b.item2, b.item3
...process data from records a and b...
END FOREACH
双循环版本的唯一优点是,您可以很容易地发现表1中值之间的中断,因为内部循环结束了。这可能是控制中断报告中的一个因素。
此外,应用程序中的排序通常是不允许的。
在他们职业生涯的前6个月学习SQL,在接下来的10年里从不学习其他任何东西。特别是没有学习或有效地使用窗口/分析SQL特性。特别是over()和partition by的使用。
窗口函数,比如聚合 函数时,对对象进行聚合 定义的行集(组),但是 而不是返回一个值 组,窗口函数可以返回 每个组有多个值。
请参阅O'Reilly SQL Cookbook附录A,以获得窗口函数的良好概述。
以下是我的前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 Server中查找重复的行
- 从DateTime中提取小时(SQL Server 2005)
- LEFT OUTER JOIN如何返回比左表中存在的记录更多的记录?
- 如何用SQL语句计算百分比
- Postgres唯一约束与索引
- SQL Server动态PIVOT查询?
- MySQL对重复键更新在一个查询中插入多行
- 向现有表添加主键
- 使用电子邮件地址为主键?
- MySQL:如何复制行,但改变几个字段?
- 不能删除或更新父行:外键约束失败
- MongoDB在v4之前不兼容ACID意味着什么?
- SQL WHERE ID IN (id1, id2,…idn)
- 最常见的SQL反模式是什么?
- 错误:没有唯一的约束匹配给定的键引用表"bar"