이 두 쿼리를 비교하십시오. 조인 기준이나 WHERE
절 에 필터를 적용하는 것이 더 빠릅니까? 가능한 한 빨리 결과 세트를 줄이기 때문에 조인 기준에서 더 빠르다고 항상 느꼈지만 확실하지 않습니다.
나는 몇 가지 테스트를 만들어 볼 것이지만 또한 어떤 것이 더 명확하게 읽을 수 있는지에 대한 의견을 얻고 싶었습니다.
쿼리 1
SELECT *
FROM TableA a
INNER JOIN TableXRef x
ON a.ID = x.TableAID
INNER JOIN TableB b
ON x.TableBID = b.ID
WHERE a.ID = 1 /* <-- Filter here? */
쿼리 2
SELECT *
FROM TableA a
INNER JOIN TableXRef x
ON a.ID = x.TableAID
AND a.ID = 1 /* <-- Or filter here? */
INNER JOIN TableB b
ON x.TableBID = b.ID
편집하다
몇 가지 테스트를 실행 한 결과 결과는 실제로 매우 가깝지만 WHERE
절은 실제로 약간 더 빠릅니다! =)
WHERE
절에 필터를 적용하는 것이 더 합리적이라는 데 절대적으로 동의합니다 . 성능에 미치는 영향에 대해 궁금했습니다.
ELAPSED TIME WHERE CRITERIA : 143016 ms
ELAPSED TIME JOIN CRITERIA : 143256 ms
테스트
SET NOCOUNT ON;
DECLARE @num INT,
@iter INT
SELECT @num = 1000, -- Number of records in TableA and TableB, the cross table is populated with a CROSS JOIN from A to B
@iter = 1000 -- Number of select iterations to perform
DECLARE @a TABLE (
id INT
)
DECLARE @b TABLE (
id INT
)
DECLARE @x TABLE (
aid INT,
bid INT
)
DECLARE @num_curr INT
SELECT @num_curr = 1
WHILE (@num_curr <= @num)
BEGIN
INSERT @a (id) SELECT @num_curr
INSERT @b (id) SELECT @num_curr
SELECT @num_curr = @num_curr + 1
END
INSERT @x (aid, bid)
SELECT a.id,
b.id
FROM @a a
CROSS JOIN @b b
/*
TEST
*/
DECLARE @begin_where DATETIME,
@end_where DATETIME,
@count_where INT,
@begin_join DATETIME,
@end_join DATETIME,
@count_join INT,
@curr INT,
@aid INT
DECLARE @temp TABLE (
curr INT,
aid INT,
bid INT
)
DELETE FROM @temp
SELECT @curr = 0,
@aid = 50
SELECT @begin_where = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
INSERT @temp (curr, aid, bid)
SELECT @curr,
aid,
bid
FROM @a a
INNER JOIN @x x
ON a.id = x.aid
INNER JOIN @b b
ON x.bid = b.id
WHERE a.id = @aid
SELECT @curr = @curr + 1
END
SELECT @end_where = CURRENT_TIMESTAMP
SELECT @count_where = COUNT(1) FROM @temp
DELETE FROM @temp
SELECT @curr = 0
SELECT @begin_join = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
INSERT @temp (curr, aid, bid)
SELECT @curr,
aid,
bid
FROM @a a
INNER JOIN @x x
ON a.id = x.aid
AND a.id = @aid
INNER JOIN @b b
ON x.bid = b.id
SELECT @curr = @curr + 1
END
SELECT @end_join = CURRENT_TIMESTAMP
SELECT @count_join = COUNT(1) FROM @temp
DELETE FROM @temp
SELECT @count_where AS count_where,
@count_join AS count_join,
DATEDIFF(millisecond, @begin_where, @end_where) AS elapsed_where,
DATEDIFF(millisecond, @begin_join, @end_join) AS elapsed_join
답변
성능면에서 동일 함 (동일한 계획 생성)
논리적으로, 당신은 당신이 대체 할 경우 여전히 감각이 작동해야 INNER JOIN
로모그래퍼을 LEFT JOIN
.
귀하의 경우 이것은 다음과 같습니다.
SELECT *
FROM TableA a
LEFT JOIN
TableXRef x
ON x.TableAID = a.ID
AND a.ID = 1
LEFT JOIN
TableB b
ON x.TableBID = b.ID
아니면 이거:
SELECT *
FROM TableA a
LEFT JOIN
TableXRef x
ON x.TableAID = a.ID
LEFT JOIN
TableB b
ON b.id = x.TableBID
WHERE a.id = 1
전자 쿼리는 a.id
이외의 실제 일치 항목을 반환하지 1
않으므로 후자의 구문 (with WHERE
)은 논리적으로 더 일관성이 있습니다.
답변
내부 조인의 경우 기준을 어디에 두든 상관 없습니다. SQL 컴파일러는 둘 다 조인 아래에서 필터링이 발생하는 실행 계획으로 변환합니다 (즉, 필터 표현식이 조인 조건에있는 것처럼).
필터의 위치가 쿼리의 의미를 변경하기 때문에 외부 조인은 다른 문제입니다.
답변
두 가지 방법이있는 한.
- JOIN / ON은 테이블 결합을위한 것입니다.
- 결과 필터링을위한 WHERE
당신은 그것들을 다르게 사용할 수 있지만 그것은 항상 나에게 냄새처럼 보입니다.
문제가있을 때 성능을 처리하십시오. 그런 다음 이러한 “최적화”를 살펴볼 수 있습니다.
답변
어떤 쿼리 옵티마이 저가 센트로 …. 그들은 동일합니다.
답변
postgresql에서는 동일합니다. explain analyze
각 쿼리에 대해 수행 하면 계획이 동일하게 나오기 때문에 이것을 알고 있습니다. 이 예를 보자 :
# explain analyze select e.* from event e join result r on e.id = r.event_id and r.team_2_score=24;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------
Hash Join (cost=27.09..38.22 rows=7 width=899) (actual time=0.045..0.047 rows=1 loops=1)
Hash Cond: (e.id = r.event_id)
-> Seq Scan on event e (cost=0.00..10.80 rows=80 width=899) (actual time=0.009..0.010 rows=2 loops=1)
-> Hash (cost=27.00..27.00 rows=7 width=8) (actual time=0.017..0.017 rows=1 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> Seq Scan on result r (cost=0.00..27.00 rows=7 width=8) (actual time=0.006..0.008 rows=1 loops=1)
Filter: (team_2_score = 24)
Rows Removed by Filter: 1
Planning time: 0.182 ms
Execution time: 0.101 ms
(10 rows)
# explain analyze select e.* from event e join result r on e.id = r.event_id where r.team_2_score=24;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------
Hash Join (cost=27.09..38.22 rows=7 width=899) (actual time=0.027..0.029 rows=1 loops=1)
Hash Cond: (e.id = r.event_id)
-> Seq Scan on event e (cost=0.00..10.80 rows=80 width=899) (actual time=0.010..0.011 rows=2 loops=1)
-> Hash (cost=27.00..27.00 rows=7 width=8) (actual time=0.010..0.010 rows=1 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> Seq Scan on result r (cost=0.00..27.00 rows=7 width=8) (actual time=0.006..0.007 rows=1 loops=1)
Filter: (team_2_score = 24)
Rows Removed by Filter: 1
Planning time: 0.140 ms
Execution time: 0.058 ms
(10 rows)
둘 다 동일한 최소 및 최대 비용과 동일한 쿼리 계획을 갖습니다. 또한 최상위 쿼리에서도 team_score_2가 ‘필터’로 적용됩니다.
답변
이 조인의 배치가 성능을 결정하는 요소가 될 가능성은 거의 없습니다. 나는 tsql의 실행 계획에 대해 잘 알지 못하지만 유사한 계획에 자동으로 최적화 될 가능성이 높습니다.
답변
규칙 # 0 : 벤치 마크를 실행하고보십시오! 어느 것이 더 빠를 지 실제로 알 수있는 유일한 방법은 그것을 시도하는 것입니다. 이러한 유형의 벤치 마크는 SQL 프로파일 러를 사용하여 수행하기가 매우 쉽습니다.
또한 JOIN 및 WHERE 절로 작성된 쿼리의 실행 계획을 조사하여 어떤 차이점이 두드러 지는지 확인하십시오.
마지막으로, 다른 사람들이 말했듯이이 두 가지는 SQL Server에 내장 된 최적화 프로그램을 포함하여 괜찮은 최적화 프로그램에 의해 동일하게 처리되어야합니다.