我在寻找一些“推理规则”(类似设置操作规则或逻辑规则),我可以用它来降低复杂性或大小的SQL查询。 是否存在这样的事情? 任何文件,任何工具? 你对自己找到的任何换算公式? 这在某种程度上类似于查询优化,而不是在性能方面。
为了不同的状态吧:经与联接,子查询,工会(复)查询是否有可能(或不)将其降低到一个更简单,相当于SQL语句,它是生产相同的结果,通过使用一些转换规则?
所以,我在找喜欢的事实,大多数子查询可以重写为连接的SQL语句的等价变换。
我在寻找一些“推理规则”(类似设置操作规则或逻辑规则),我可以用它来降低复杂性或大小的SQL查询。 是否存在这样的事情? 任何文件,任何工具? 你对自己找到的任何换算公式? 这在某种程度上类似于查询优化,而不是在性能方面。
为了不同的状态吧:经与联接,子查询,工会(复)查询是否有可能(或不)将其降低到一个更简单,相当于SQL语句,它是生产相同的结果,通过使用一些转换规则?
所以,我在找喜欢的事实,大多数子查询可以重写为连接的SQL语句的等价变换。
为了不同的状态吧:经与联接,子查询,工会(复)查询是否有可能(或不)将其降低到一个更简单,相当于SQL语句,它是生产相同的结果,通过使用一些转换规则?
这正是优化为生(不是我说的,他们总是这样做很好)做的。
由于SQL
是基于集合的语言,通常有一个查询转换为其他的方法不止一种。
像这样的查询:
SELECT *
FROM mytable
WHERE col1 > @value1 OR col2 < @value2
可以转化成这样的:
SELECT *
FROM mytable
WHERE col1 > @value1
UNION
SELECT *
FROM mytable
WHERE col2 < @value2
或这个:
SELECT mo.*
FROM (
SELECT id
FROM mytable
WHERE col1 > @value1
UNION
SELECT id
FROM mytable
WHERE col2 < @value2
) mi
JOIN mytable mo
ON mo.id = mi.id
,看起来丑陋,但可以产生更好的执行计划。
其中最常见的东西做的是替换这个查询:
SELECT *
FROM mytable
WHERE col IN
(
SELECT othercol
FROM othertable
)
这一个:
SELECT *
FROM mytable mo
WHERE EXISTS
(
SELECT NULL
FROM othertable o
WHERE o.othercol = mo.col
)
在一些RDBMS
的(如PostgreSQL
), DISTINCT
和GROUP BY
使用不同的执行计划,所以有时候,最好更换一个与其他:
SELECT mo.grouper,
(
SELECT SUM(col)
FROM mytable mi
WHERE mi.grouper = mo.grouper
)
FROM (
SELECT DISTINCT grouper
FROM mytable
) mo
与
SELECT mo.grouper, SUM(col)
FROM mytable
GROUP BY
mo.grouper
在PostgreSQL
, DISTINCT
排序和GROUP BY
散列。
MySQL
缺乏FULL OUTER JOIN
,因此它可以被改写为folloing:
SELECT t1.col1, t2.col2
FROM table1 t1
LEFT OUTER JOIN
table2 t2
ON t1.id = t2.id
与
SELECT t1.col1, t2.col2
FROM table1 t1
LEFT JOIN
table2 t2
ON t1.id = t2.id
UNION ALL
SELECT NULL, t2.col2
FROM table1 t1
RIGHT JOIN
table2 t2
ON t1.id = t2.id
WHERE t1.id IS NULL
,但看到这篇文章中我就如何更有效地做这个博客MySQL
:
FULL OUTER JOIN
在MySQL 在这个层次查询Oracle
:
SELECT DISTINCT(animal_id) AS animal_id
FROM animal
START WITH
animal_id = :id
CONNECT BY
PRIOR animal_id IN (father, mother)
ORDER BY
animal_id
可以转化成这样的:
SELECT DISTINCT(animal_id) AS animal_id
FROM (
SELECT 0 AS gender, animal_id, father AS parent
FROM animal
UNION ALL
SELECT 1, animal_id, mother
FROM animal
)
START WITH
animal_id = :id
CONNECT BY
parent = PRIOR animal_id
ORDER BY
animal_id
,后者是更高性能的。
看到这篇文章在我的博客的执行计划的详细信息:
要寻找重叠的给定范围内的所有范围,可以使用下面的查询:
SELECT *
FROM ranges
WHERE end_date >= @start
AND start_date <= @end
,但在SQL Server
这种更复杂的查询产生相同的结果速度快:
SELECT *
FROM ranges
WHERE (start_date > @start AND start_date <= @end)
OR (@start BETWEEN start_date AND end_date)
,并相信与否,我在我的博客上这样的文章太:
SQL Server
还缺乏一个有效的方式做到累积的集合体,所以这个查询:
SELECT mi.id, SUM(mo.value) AS running_sum
FROM mytable mi
JOIN mytable mo
ON mo.id <= mi.id
GROUP BY
mi.id
可以使用,主帮助我更有效地重写,游标(你听我的权利: cursors
, more efficiently
和SQL Server
一句话)。
请参阅本文中我对如何做博客:
有某一种,用于有效率达搜索的货币,像这样的金融应用中通常遇到的查询Oracle
:
SELECT TO_CHAR(SUM(xac_amount * rte_rate), 'FM999G999G999G999G999G999D999999')
FROM t_transaction x
JOIN t_rate r
ON (rte_currency, rte_date) IN
(
SELECT xac_currency, MAX(rte_date)
FROM t_rate
WHERE rte_currency = xac_currency
AND rte_date <= xac_date
)
该查询可重写大量使用相等的条件,允许一个HASH JOIN
代替NESTED LOOPS
:
WITH v_rate AS
(
SELECT cur_id AS eff_currency, dte_date AS eff_date, rte_rate AS eff_rate
FROM (
SELECT cur_id, dte_date,
(
SELECT MAX(rte_date)
FROM t_rate ri
WHERE rte_currency = cur_id
AND rte_date <= dte_date
) AS rte_effdate
FROM (
SELECT (
SELECT MAX(rte_date)
FROM t_rate
) - level + 1 AS dte_date
FROM dual
CONNECT BY
level <=
(
SELECT MAX(rte_date) - MIN(rte_date)
FROM t_rate
)
) v_date,
(
SELECT 1 AS cur_id
FROM dual
UNION ALL
SELECT 2 AS cur_id
FROM dual
) v_currency
) v_eff
LEFT JOIN
t_rate
ON rte_currency = cur_id
AND rte_date = rte_effdate
)
SELECT TO_CHAR(SUM(xac_amount * eff_rate), 'FM999G999G999G999G999G999D999999')
FROM (
SELECT xac_currency, TRUNC(xac_date) AS xac_date, SUM(xac_amount) AS xac_amount, COUNT(*) AS cnt
FROM t_transaction x
GROUP BY
xac_currency, TRUNC(xac_date)
)
JOIN v_rate
ON eff_currency = xac_currency
AND eff_date = xac_date
尽管是笨重的地狱,后者查询是6
快倍。
这里的主要思想是取代<=
带=
,这就要求建立一个内存中的日历表。 到JOIN
用。
这里有几个来自与Oracle 8和9的工作(当然,有时做相反可能使查询更简单或更快):
括号可以,如果他们不用于覆盖运算符优先级被删除。 一个简单的例子是,当所有的在布尔运算符where
子句是相同的: where ((a or b) or c)
等同于where a or b or c
。
一个子查询可以经常(如果不总是) 与简化它的主查询合并 。 根据我的经验,这往往可以提高性能显着:
select foo.a,
bar.a
from foomatic foo,
bartastic bar
where foo.id = bar.id and
bar.id = (
select ban.id
from bantabulous ban
where ban.bandana = 42
)
;
相当于
select foo.a,
bar.a
from foomatic foo,
bartastic bar,
bantabulous ban
where foo.id = bar.id and
bar.id = ban.id and
ban.bandana = 42
;
使用ANSI联接 WHERE子句中的真正有趣的部分分离出来很多“代码猴子”的逻辑:以前的查询相当于
select foo.a,
bar.a
from foomatic foo
join bartastic bar on bar.id = foo.id
join bantabulous ban on ban.id = bar.id
where ban.bandana = 42
;
如果您要检查行的存在,不使用count(*),而是使用任何rownum = 1
或将查询在where exists
子句仅取一排,而不是全部。
作为@Quassnoi提到的,优化工具往往做得很好。 帮助它的方法之一是确保指标和统计数据是最新的,并为您的查询工作负载存在,合适的索引。
我想以取代连接查询所有类型的子选择。
这一个是显而易见的:
SELECT *
FROM mytable mo
WHERE EXISTS
(
SELECT *
FROM othertable o
WHERE o.othercol = mo.col
)
通过
SELECT mo.*
FROM mytable mo inner join othertable o on o.othercol = mo.col
而这一次低估:
SELECT *
FROM mytable mo
WHERE NOT EXISTS
(
SELECT *
FROM othertable o
WHERE o.othercol = mo.col
)
通过
SELECT mo.*
FROM mytable mo left outer join othertable o on o.othercol = mo.col
WHERE o.othercol is null
它可以帮助数据库管理系统选择在一个大的请求良好的执行计划。
我喜欢在一个团队中每个人都遵循一套标准,以使代码可读性,可维护性,易于理解,耐水洗等。:)
这里存在一些更多的东西有哪些你最有用的数据库标准是什么?
由于SQL的性质,你绝对必须要知道的任何重构的性能影响。 重构SQL应用程序是一个沉重强调性能重构一个很好的资源(见第5章)。
虽然简化可能不等于优化,简化,可以以书面可读SQL代码,这又将是能够检查你的SQL代码为概念的正确性至关重要的(不是语法正确,你的开发环境应该检查你)很重要。 在我看来,在一个理想的世界,我们会写最简单的,可读的SQL代码,然后优化器将重写SQL代码,以任何形式(也许更详细)会跑的最快。
我发现SQL语句的这种思维的基础上设定的逻辑是非常有用的,特别是如果我需要在那里合并条款或找出一个where子句的复杂否定。 我用的是布尔代数的法律在这种情况下。
为简化最重要的where子句可能是德摩根定律(注意,“·”是“与”和“+”是“或”):
这意味着在SQL中:
NOT (expr1 AND expr2) -> NOT expr1 OR NOT expr2
NOT (expr1 OR expr2) -> NOT expr1 AND NOT expr2
这些法律可以在简化非常有用的地方,有很多的嵌套的条款AND
和OR
部分。
这也是有用的记得声明field1 IN (value1, value2, ...)
等同于field1 = value1 OR field1 = value2 OR ...
。 这使您可以否定IN ()
两种方法之一:
NOT field1 IN (value1, value2) -- for longer lists
NOT field1 = value1 AND NOT field1 = value2 -- for shorter lists
一个子查询可以被视为这种方式也。 例如,这种否定where子句:
NOT (table1.field1 = value1 AND EXISTS (SELECT * FROM table2 WHERE table1.field1 = table2.field2))
可改写为:
NOT table1.field1 = value1 OR NOT EXISTS (SELECT * FROM table2 WHERE table1.field1 = table2.field2))
这些法律不会告诉你如何使用连接到使用子查询的SQL查询转换为一个,但布尔逻辑可以帮助您了解连接类型和你的查询应该返回。 例如,具有表A
和B
,一个INNER JOIN
是像A AND B
,一个LEFT OUTER JOIN
是像(A AND NOT B) OR (A AND B)
其简化为A OR (A AND B)
和一个FULL OUTER JOIN
是A OR (A AND B) OR B
,其简化为A OR B
。
我的方法是学习一般,特别是关系代数关系理论。 然后,学会发现在SQL用来实现从关系代数运算符的构造(例如通用量化又名师)和微积分(如存在量词)。 在疑难杂症的是,SQL在关系模型如空值,这可能是最好的重构远无论如何没有的功能。 推荐阅读: SQL和关系理论:如何编写准确的SQL代码由CJ日期 。
在这方面,我不相信“的事实,大多数子查询可以重写为连接”代表的简化。
就拿这个查询,例如:
SELECT c
FROM T1
WHERE c NOT IN ( SELECT c FROM T2 );
重写使用JOIN
SELECT DISTINCT T1.c
FROM T1 NATURAL LEFT OUTER JOIN T2
WHERE T2.c IS NULL;
该联接是更详细的!
可替换地,识别该构建体被实施上的投影的反连接c
例如伪algrbra
T1 { c } antijoin T2 { c }
简化使用关系运算符:
SELECT c FROM T1 EXCEPT SELECT c FROM T2;