개별 쿼리가 조인보다 빠릅니까?


44

개념적 질문 : 개별 쿼리가 조인보다 빠르 거나 클라이언트 측에서 원하는 모든 정보를 하나의 SELECT 문 으로 압축 하거나 편리한 것처럼 많이 사용해야합니까?

TL; DR : 경우 에 가입 쿼리가 개별 쿼리를 실행하는 것보다 더 오래 걸립니다,이 내 잘못, 또는이 기대할 수 있나요?

첫째, 나는 데이터베이스에 정통하지 않기 때문에 나일 수도 있지만 여러 테이블에서 정보를 가져와야 할 때 개별 테이블에 대한 여러 쿼리를 통해이 정보를 얻는 것이 "종종"더 빠르다는 것을 알았습니다. 하나의 쿼리로 모든 데이터를 얻을 수있는 (복잡한) 조인 된 쿼리를 작성하려고 클라이언트 측에서 데이터를 함께 패치합니다.

나는 매우 간단한 예를 하나 모아 보았습니다.

SQL 바이올린

스키마 설정 :

CREATE TABLE MASTER 
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);

CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);

INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');

CREATE SEQUENCE SEQ_DATA_ID;

INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);

쿼리 A :

select NAME from MASTER
where ID = 1

결과 :

| NAME |
--------
|  One |

쿼리 B :

select ID, VALUE from DATA
where MASTER_ID = 1

결과 :

| ID | VALUE |
--------------
|  1 |   1.3 |
|  2 |   1.5 |
|  3 |   1.7 |

쿼리 C :

select M.NAME, D.ID, D.VALUE 
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1

결과 :

| NAME | ID | VALUE |
---------------------
|  One |  1 |   1.3 |
|  One |  2 |   1.5 |
|  One |  3 |   1.7 |

물론, 나는 이것으로 성능을 측정하지는 않았지만 관찰 할 수 있습니다.

  • 쿼리 A + B는 쿼리 C와 동일한 양의 사용 가능한 정보를 반환합니다.
  • A + B는 1 + 2x3 == 7 "데이터 셀"을 클라이언트에 반환해야합니다.
  • C는 클라이언트에게 3x3 == 9 "Data Cells"를 반환해야합니다.

이것으로부터 일반화 (있는 그대로 가져옵니다) :

조인 된 쿼리는 항상 같은 양의 정보를받는 개별 쿼리보다 더 많은 데이터를 반환해야합니다. 데이터베이스가 데이터를 함께 모아야하기 때문에 큰 데이터 세트의 경우 데이터베이스는 개별 쿼리보다 단일 결합 된 쿼리에 대해 더 많은 작업을 수행해야한다고 가정 할 수 있습니다.

클라이언트 측 쿼리를 여러 쿼리로 나누면 더 나은 성능을 얻는다는 것을 알았을 때, 이것은 갈 길이거나 오히려 결합 된 쿼리를 엉망으로 만들었다는 것을 의미합니까?


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
잭 더글러스

1
나는 벤치 마크를 실행하고 결과 를 Medium 기사에 게시했습니다 . 여기에 답변을 추가했지만 이미 다른 질문에 대해 답변했으며 여러 질문에 동일한 답변을 게시하는 것은 어리둥절합니다 .
벤자민

답변:


45

개별 쿼리가 조인보다 빠르거나 클라이언트 측에서 원하는 모든 정보를 하나의 SELECT 문으로 압축하거나 편리한 것처럼 많은 수를 사용해야합니까?

어떤 성능 시나리오에서는 에있는 테스트 및 측정 빠르게 확인할하는 솔루션을 .

즉, 적절하게 조정 된 데이터베이스에서 조인 된 결과 집합이 소스 행을 클라이언트에 반환 한 다음 조인하는 것보다 빠르며 확장 성이 향상되는 경우가 거의 항상 있습니다. 특히 입력 세트가 크고 결과 세트가 작은 경우 두 전략의 맥락에서 다음 쿼리를 고려하십시오. 각 행이 5GB 인 두 개의 테이블을 결과 행 100 개로 결합하십시오. 그것은 극단적이지만 내 요점을 알 수 있습니다.

여러 테이블에서 정보를 가져와야하는 경우 개별 테이블에 대한 여러 쿼리를 통해 (간단한 내부 조인을 포함 할 수 있음)이 정보를 얻는 것이 "보통"더 빠르다는 것을 알았습니다. 하나의 쿼리로 모든 데이터를 얻을 수있는 (복잡한) 조인 된 쿼리를 작성합니다.

데이터베이스 스키마 또는 인덱스를 개선하여 사용자가 던지는 쿼리를 더 잘 처리 할 수 ​​있습니다.

조인 된 쿼리는 항상 같은 양의 정보를받는 개별 쿼리보다 더 많은 데이터를 반환해야합니다.

일반적으로 그렇지 않습니다. 입력 집합이 크더라도 대부분의 경우 결과 집합은 입력 합계보다 훨씬 작습니다.

응용 프로그램에 따라 클라이언트에 반환되는 매우 큰 쿼리 결과 집합은 즉각적인 위험 신호입니다. 즉, 데이터베이스에 더 가까이 갈 수없는 이러한 큰 데이터 집합으로 클라이언트가 수행하는 작업은 무엇입니까? 사용자에게 1,000,000 개의 행을 표시하는 것이 가장 의심 스럽습니다. 네트워크 대역폭도 유한 한 자원입니다.

데이터베이스가 데이터를 함께 모아야하기 때문에 큰 데이터 세트의 경우 데이터베이스는 개별 쿼리보다 단일 결합 된 쿼리에 대해 더 많은 작업을 수행해야한다고 가정 할 수 있습니다.

반드시 그런 것은 아닙니다. 데이터가 올바르게 인덱싱되면 대량의 데이터를 스캔하지 않고도 데이터베이스에서 조인 작업을보다 효율적으로 수행 할 수 있습니다. 또한 관계형 데이터베이스 엔진은 결합을 위해 낮은 수준에서 특별히 최적화됩니다 . 클라이언트 스택이 아닙니다.

클라이언트 측 쿼리를 여러 쿼리로 나누면 더 나은 성능을 얻는다는 것을 알았을 때, 이것은 갈 길이거나 오히려 결합 된 쿼리를 엉망으로 만들었다는 것을 의미합니까?

데이터베이스와 관련하여 경험이 없다고 말 했으므로 데이터베이스 디자인 및 성능 조정에 대해 자세히 배우는 것이 좋습니다. 나는 그것이 문제가 여기에 있다고 확신합니다. 비효율적으로 작성된 SQL 쿼리도 가능하지만 문제가 거의없는 간단한 스키마가 있습니다.

이제는 성능을 향상시킬 다른 방법이 없다고 말하는 것은 아닙니다. 중대형 데이터 세트를 스캔하여 어떤 종류의 캐싱 메커니즘을 사용하려는 경우 클라이언트로 리턴하도록 선택할 수있는 시나리오가 있습니다. 캐싱은 훌륭하지만 디자인에 복잡성을 초래합니다. 캐싱은 응용 프로그램에 적합하지 않을 수도 있습니다.

어디에도 언급되지 않은 한 가지는 데이터베이스에서 반환 된 데이터의 일관성을 유지하는 것입니다. 별도의 쿼리를 사용하는 경우 모든 쿼리 집합에 대해 스냅 샷 격리 형식을 사용하지 않는 한 여러 요인으로 인해 일관되지 않은 데이터가 반환 될 가능성이 높습니다.


네트워크 대역폭의 경우 +1은 유한 리소스입니다.
Hari Harker

OP는 JOINed 데이터 결과 세트가 항상 더 크다고 말합니다. > 조인 된 쿼리는 항상 개별 쿼리보다 많은 데이터를 반환해야합니다. 나는 이것이 객관적으로 사실이라고 생각합니다 (> =의 경우). 예를 들어 결과 세트의 크기가 다르므로 와이어를 통해 더 많은 데이터가 필요합니다. 이것이 사실이 아닌 예가 있습니까? 필자가 Authors-> Posts에 가입하고 Authors에 "biography"라는 필드가 1MB JSON 필드 인 경우 100 개 게시물의 저자에게는 100MB 대 1MB를 전송합니다. 이것이 잘못 되었습니까?
hytromo

6

물론, 나는 이것들로 어떤 성능도 측정하지 않았다.

좋은 샘플 코드를 모았습니다. SQL Fiddle의 타이밍을 보셨습니까? 약간의 비과학적인 성능 테스트조차도 데모에서 쿼리 3이 쿼리 1 또는 2와 별도로 실행되는 데 거의 같은 시간이 걸린다는 것을 보여줍니다. 결합 된 1과 2는 3만큼 약 2 배가 걸리며 이는 클라이언트 측 조인이 수행되기 전입니다.

데이터를 늘리면 쿼리 1과 2의 속도가 달라 지지만 데이터베이스 조인은 여전히 ​​더 빠릅니다.

내부 조인이 데이터를 제거하는 경우 어떻게 될지 고려해야합니다.


2

쿼리 최적화 프로그램도 고려해야합니다. 그 역할은 선언적 SQL을 가져 와서 절차 적 단계로 변환하는 것입니다. 절차 단계의 가장 효율적인 조합을 찾으려면 인덱스 사용, 정렬, 중간 결과 세트 캐싱 및 기타 모든 유형의 조합을 검사합니다. 아주 간단한 쿼리처럼 보이더라도 순열 수는 너무 커질 수 있습니다.

최상의 계획을 찾기 위해 수행 된 많은 계산은 테이블 내의 데이터 분포에 의해 이루어집니다. 이러한 분포는 샘플링되어 통계 개체로 저장됩니다. 이것이 잘못되면 옵티마이 저가 잘못된 선택을하게합니다. 계획 초기에 잘못된 선택은 나중에 눈덩이 효과에서 더 나쁜 선택으로 이어집니다.

중간 규모의 쿼리가 적당한 양의 데이터를 반환하는 데 몇 분이 걸리는지는 알 수 없습니다. 그런 다음 올바른 색인 작성 및 올바른 통계는이를 밀리 초로 줄입니다.


-3

여러 쿼리가 갈 길입니다. 이와 같은 간단한 시나리오를 처리하는 경우 쿼리 최적화 프로그램의 비용 오버 헤드가 중요합니다. 데이터가 많을수록 조인 (중복 행)의 네트워크 비 효율성이 발생합니다. 데이터가 많을수록 효율성이 높아집니다.

결국, 당신이 경험하는 것은 많은 개발자들이 보는 것입니다. DBA는 항상 "아니요, 조인하십시오"라고 말하지만 실제로는이 경우 여러 간단한 선택을하는 것이 더 빠릅니다.


5
조인에는 "네트워크 비 효율성"이 없습니다. 모든 것이 데이터베이스 서버에서 발생하므로 네트워크가 없습니다 (db 링크를 통해 조인하지 않는 한!)
Chris Saxon

2
네트워크 계층에 압축이 있는지 여부를 고려할 수 있습니다. Oracle의 SQL * Net은 동일한 열에서 반복되는 값이 효율적으로 압축되도록합니다.
David Aldridge

3
@TomTom 당신은 (David Aldridge 포인트, 압축 문제와 같이) 포인트가 있거나 없을 수 있지만 문구가 혼동됩니다. "조인의 네트워크 비 효율성" ? 정말로, 그것을 고치면 의미가 분명합니다.
ypercubeᵀᴹ

@ChrisSaxon 확실히, 당신은 "title-> base-> table-rows"리포트를위한 테이블이 있고이 3 개의 테이블을 내부에 조인하기 위해 모든 행이 필요합니다. 각 테이블에는 긴 varchar가 있으므로 이러한 긴 varchar를 반복하는 모든 행에 대해 발생합니다. 응용 프로그램 계층은 이러한 모든 문자열에 메모리를 할당 한 다음 모델에 맞게 그룹화해야합니다. 그래서 이것이 그가 의미하는
MIKE

@MIKE는 조인이 아닌 선택한 식에 따라 다릅니다. 네트워크 압축이있을 수 있습니다. Oracle Database SQL * Net에서 중복 된 중복 값을 제거함 nicetheory.io/2018/01/11/…
Chris Saxon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.