SQL 使用 OR 子句的查询性能
SQL query performance with OR clause
这个 SQL 查询需要 10 秒:
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON((e.perimeterId = a.idA AND e.level = 3)
OR (e.perimeterId = b.idB AND e.level = 2)
OR (e.perimeterId = c.idC AND e.level = 1)
OR (e.perimeterId = d.idD AND e.level = 0))
将 OR 子句更改为 CASE,查询需要 3 秒:
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON (
CASE e.level
when 3 then a.idA
when 2 then b.idB
when 1 then c.idC
when 0 then d.idD
END
) = e.perimeterId
如果我用单独的 OR 子句执行查询,查询会立即执行
使用我们的 OR 子句:
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON (e.perimeterId = a.idX AND e.level = X)
如何重写我的查询以立即执行或以高性能执行?
您只需要来自 e
的列,所以我会使用 exists
:
来编写
SELECT e.*
FROM E e
WHERE EXISTS (SELECT 1
FROM a
WHERE e.perimeterId = a.idA AND e.level = 3
) OR
EXISTS (SELECT 1
FROM a JOIN
b
ON a.idB = b.idB
WHERE e.perimeterId = b.idA AND e.level = 2
) OR
EXISTS (SELECT 1
FROM a JOIN
b
ON a.idB = b.idB JOIN
c
ON c.idC = b.idC
WHERE e.perimeterId = c.idA AND e.level = 1
) OR
EXISTS (SELECT 1
FROM a JOIN
b
ON a.idB = b.idB JOIN
c
ON c.idC = b.idC JOIN
d
ON d.idD = c.idD
WHERE e.perimeterId = d.idA AND e.level = 0
);
我不是 100% 确定子查询中需要 JOIN
,但无论如何我都保留了它们。
1)在a.idB、b.idB、b.idC、c.idC、c.idD、d.idD、[=21=上创建索引], e.level
2)
试试这个
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON(e.perimeterId = a.idA AND e.level = 3)
UNION ALL
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON(e.perimeterId = a.idB AND e.level = 2)
UNION ALL
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON(e.perimeterId = a.idC AND e.level = 1)
UNION ALL
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON(e.perimeterId = a.idD AND e.level = 0)
大多数性能问题都可以通过构建良好的索引来解决,如果您不必创建相应的过滤器列,则在您的子句中始终尝试使用主索引。
这个 SQL 查询需要 10 秒:
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON((e.perimeterId = a.idA AND e.level = 3)
OR (e.perimeterId = b.idB AND e.level = 2)
OR (e.perimeterId = c.idC AND e.level = 1)
OR (e.perimeterId = d.idD AND e.level = 0))
将 OR 子句更改为 CASE,查询需要 3 秒:
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON (
CASE e.level
when 3 then a.idA
when 2 then b.idB
when 1 then c.idC
when 0 then d.idD
END
) = e.perimeterId
如果我用单独的 OR 子句执行查询,查询会立即执行 使用我们的 OR 子句:
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON (e.perimeterId = a.idX AND e.level = X)
如何重写我的查询以立即执行或以高性能执行?
您只需要来自 e
的列,所以我会使用 exists
:
SELECT e.*
FROM E e
WHERE EXISTS (SELECT 1
FROM a
WHERE e.perimeterId = a.idA AND e.level = 3
) OR
EXISTS (SELECT 1
FROM a JOIN
b
ON a.idB = b.idB
WHERE e.perimeterId = b.idA AND e.level = 2
) OR
EXISTS (SELECT 1
FROM a JOIN
b
ON a.idB = b.idB JOIN
c
ON c.idC = b.idC
WHERE e.perimeterId = c.idA AND e.level = 1
) OR
EXISTS (SELECT 1
FROM a JOIN
b
ON a.idB = b.idB JOIN
c
ON c.idC = b.idC JOIN
d
ON d.idD = c.idD
WHERE e.perimeterId = d.idA AND e.level = 0
);
我不是 100% 确定子查询中需要 JOIN
,但无论如何我都保留了它们。
1)在a.idB、b.idB、b.idC、c.idC、c.idD、d.idD、[=21=上创建索引], e.level
2) 试试这个
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON(e.perimeterId = a.idA AND e.level = 3)
UNION ALL
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON(e.perimeterId = a.idB AND e.level = 2)
UNION ALL
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON(e.perimeterId = a.idC AND e.level = 1)
UNION ALL
SELECT * FROM A a
JOIN B b on a.idB = b.idB
JOIN C c on b.idC = c.idC
JOIN D d on c.idD = d.idD
JOIN E e ON(e.perimeterId = a.idD AND e.level = 0)
大多数性能问题都可以通过构建良好的索引来解决,如果您不必创建相应的过滤器列,则在您的子句中始终尝试使用主索引。