쿼리 실행 연산자

소개

이 페이지에서는 Spanner 쿼리 실행 계획에 사용되는 연산자를 자세히 설명합니다. Google Cloud 콘솔을 사용하여 특정 쿼리의 실행 계획을 검색하는 방법은 Spanner의 쿼리 실행 방법 이해를 참조하세요.

이 페이지의 쿼리 및 실행 계획은 다음 데이터베이스 스키마를 기반으로 합니다.

CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
  BirthDate  DATE
) PRIMARY KEY(SingerId);

CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);

CREATE TABLE Albums (
  SingerId        INT64 NOT NULL,
  AlbumId         INT64 NOT NULL,
  AlbumTitle      STRING(MAX),
  MarketingBudget INT64
) PRIMARY KEY(SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);

CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget);

CREATE TABLE Songs (
  SingerId  INT64 NOT NULL,
  AlbumId   INT64 NOT NULL,
  TrackId   INT64 NOT NULL,
  SongName  STRING(MAX),
  Duration  INT64,
  SongGenre STRING(25)
) PRIMARY KEY(SingerId, AlbumId, TrackId),
  INTERLEAVE IN PARENT Albums ON DELETE CASCADE;

CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC), INTERLEAVE IN Albums;

CREATE INDEX SongsBySongName ON Songs(SongName);

CREATE TABLE Concerts (
  VenueId      INT64 NOT NULL,
  SingerId     INT64 NOT NULL,
  ConcertDate  DATE NOT NULL,
  BeginTime    TIMESTAMP,
  EndTime      TIMESTAMP,
  TicketPrices ARRAY<INT64>
) PRIMARY KEY(VenueId, SingerId, ConcertDate);

다음과 같은 데이터 조작 언어(DML) 문을 사용하여 이러한 테이블에 데이터를 추가할 수 있습니다.

INSERT INTO Singers (SingerId, FirstName, LastName, BirthDate)
VALUES (1, "Marc", "Richards", "1970-09-03"),
       (2, "Catalina", "Smith", "1990-08-17"),
       (3, "Alice", "Trentor", "1991-10-02"),
       (4, "Lea", "Martin", "1991-11-09"),
       (5, "David", "Lomond", "1977-01-29");

INSERT INTO Albums (SingerId, AlbumId, AlbumTitle)
VALUES (1, 1, "Total Junk"),
       (1, 2, "Go, Go, Go"),
       (2, 1, "Green"),
       (2, 2, "Forever Hold Your Peace"),
       (2, 3, "Terrified"),
       (3, 1, "Nothing To Do With Me"),
       (4, 1, "Play");

INSERT INTO Songs (SingerId, AlbumId, TrackId, SongName, Duration, SongGenre)
VALUES (2, 1, 1, "Let's Get Back Together", 182, "COUNTRY"),
       (2, 1, 2, "Starting Again", 156, "ROCK"),
       (2, 1, 3, "I Knew You Were Magic", 294, "BLUES"),
       (2, 1, 4, "42", 185, "CLASSICAL"),
       (2, 1, 5, "Blue", 238, "BLUES"),
       (2, 1, 6, "Nothing Is The Same", 303, "BLUES"),
       (2, 1, 7, "The Second Time", 255, "ROCK"),
       (2, 3, 1, "Fight Story", 194, "ROCK"),
       (3, 1, 1, "Not About The Guitar", 278, "BLUES");

Leaf 연산자

Leaf 연산자는 하위 요소가 없는 연산자입니다. Leaf 연산자 유형은 다음과 같습니다.

배열 중첩 해제

배열 중첩 해제 연산자는 입력 배열을 요소 행으로 평면화합니다. 각 결과 행에는 배열의 실제 값과 0부터 시작하는 배열 내 위치(선택사항)가 들어 있는 최대 2개의 열이 포함됩니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT a, b FROM UNNEST([1,2,3]) a WITH OFFSET b;

이 쿼리는 a 열에 있는 [1,2,3] 배열을 평면화하고 b 열에 배열 위치를 표시합니다.

결과는 다음과 같습니다.

a b
1 0
2 1
3 2

다음은 실행 계획입니다.

배열 중첩 해제 연산자

관계 생성

관계 생성 연산자는 0개 이상의 행을 반환합니다.

단위 관계

단위 관계는 1개의 행을 반환합니다. 이것은 관계 생성 연산자의 특별한 경우입니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT 1 + 2 AS Result;

결과는 다음과 같습니다.

결과
3

다음은 실행 계획입니다.

단위 관계 연산자

빈 관계

빈 관계는 행을 반환하지 않습니다. 이것은 관계 생성 연산자의 특별한 경우입니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT * FROM Albums LIMIT 0

결과는 다음과 같습니다.

No results

다음은 실행 계획입니다.

빈 관계 연산자

스캔

스캔 연산자는 행 소스를 스캔하여 행을 반환합니다. 다음은 스캔 연산자의 유형입니다.

  • 테이블 스캔: 테이블에서 스캔이 실행됩니다.
  • 색인 스캔: 색인에서 스캔이 실행됩니다.
  • 배치 스캔: 다른 관계형 연산자에서 생성된 중간 테이블(예: 분산 교차 적용에서 생성된 테이블)에서 스캔이 실행됩니다.

가능할 때마다 Spanner는 스캔의 일부로 키에 간단한 조건자를 적용합니다. 조건자가 적용되면 스캔 시 전체 테이블 또는 색인을 읽을 필요가 없으므로 스캔이 보다 효율적으로 실행됩니다. 조건자는 실행 계획에 KeyPredicate: column=value 형식으로 나타납니다.

최악의 경우에는 쿼리가 테이블에 있는 행을 모두 조회해야 할 수 있습니다. 이러한 상황은 전체 스캔으로 이어지고, 실행 계획에 full scan: true로 표시됩니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT s.LastName
FROM singers@{FORCE_INDEX=SingersByFirstLastName} AS s
WHERE s.FirstName = 'Catalina';

결과는 다음과 같습니다.

LastName
Smith

다음은 실행 계획입니다.

스캔 연산자

실행 계획에서 최상위 수준의 분산 통합 연산자는 원격 서버로 하위 계획을 보냅니다. 각 하위 계획에는 결과 직렬화 연산자와 색인 스캔 연산자가 있습니다. 조건자 Key Predicate: FirstName = 'Catalina'는 색인 SingersByFirstLastname에서 FirstNameCatalina인 행으로 스캔을 제한합니다. 색인 스캔 출력은 결과 직렬화 연산자로 반환됩니다.

단항 연산자

단항 연산자는 하나의 관계형 하위 요소가 있는 연산자입니다.

다음 연산자들이 단항 연산자입니다.

집계

집계 연산자는 GROUP BY SQL 문과 집계 함수(예: COUNT)를 실행합니다. 집계 연산자의 입력은 키 열에 정렬된 그룹(또는 GROUP BY가 없는 경우 단일 그룹)으로 논리적으로 분할됩니다. 각 그룹에 대해 0개 이상의 집계가 계산됩니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT s.SingerId, AVG(s.duration) AS average, COUNT(*) AS count
FROM Songs AS s
GROUP BY SingerId;

이 쿼리는 SingerId를 기준으로 그룹화를 수행한 후 AVG 집계와 COUNT 집계를 수행합니다.

결과는 다음과 같습니다.

SingerId average count
3 278 1
2 225.875 8

다음은 실행 계획입니다.

집계 연산자

집계 연산자는 스트림 기반 또는 해시 기반일 수 있습니다. 위의 실행 계획은 스트림 기반 집계를 보여줍니다. 스트림 기반 집계는 이미 사전 정렬된 입력을 읽고(GROUP BY가 있는 경우) 차단 없이 그룹을 컴퓨팅합니다. 해시 기반 집계는 여러 입력 행의 증분 집계를 동시에 유지하기 위해 해시 테이블을 작성합니다. 스트림 기반 집계는 해시 기반 집계보다 메모리를 적게 사용하고 빠르지만 입력을 정렬해야 합니다(키 열 또는 보조 색인 사용).

분산 시나리오의 경우, 집계 연산자를 로컬/전역 쌍으로 분리할 수 ​​있습니다. 각 원격 서버는 입력 행에서 로컬 집계를 수행한 후 결과를 루트 서버로 반환합니다. 루트 서버는 전역 집계를 수행합니다.

변형 적용

변형 적용 연산자는 데이터 조작 언어(DML) 문의 변형을 테이블에 적용합니다. 이것은 DML 문의 쿼리 계획에서 최상위 연산자입니다.

예를 들어 다음 쿼리를 사용합니다.

DELETE FROM Singers
WHERE FirstName = 'Alice';

결과는 다음과 같습니다.

4 rows deleted
This statement deleted 4 rows and did not return any rows.

다음은 실행 계획입니다.

변형 적용 연산자

배치 만들기

배치 만들기 연산자는 입력 행을 하나의 시퀀스로 일괄 처리합니다. 배치 만들기 연산은 일반적으로 분산 교차 적용 연산의 일부로 수행됩니다. 입력 행은 일괄 처리 중에 다시 정렬될 수 있습니다. 일괄 연산자를 실행할 때마다 일괄 처리되는 입력 행 수는 달라집니다.

실행 계획에서 배치 만들기 연산자의 예시는 분산 교차 적용 연산자를 참조하세요.

컴퓨팅

컴퓨팅 연산자는 입력 행을 읽고 스칼라 표현식을 통해 계산된 추가 열을 한 개 이상 추가하여 출력을 생성합니다. 실행 계획에서 컴퓨팅 연산자의 예시를 보려면 전체 통합 연산자를 참조하세요.

컴퓨팅 구조체

컴퓨팅 구조체 연산자는 각 입력 열의 필드가 있는 구조체 변수를 만듭니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT FirstName,
       ARRAY(SELECT AS STRUCT song.SongName, song.SongGenre
             FROM Songs AS song
             WHERE song.SingerId = singer.SingerId)
FROM singers AS singer
WHERE singer.SingerId = 3;

결과는 다음과 같습니다.

FirstName 미지정
Alice [["Not About The Guitar","BLUES"]]

다음은 실행 계획입니다.

컴퓨팅 구조체 연산자

실행 계획에서 배열 서브 쿼리 연산자는 분산 통합 연산자로부터 입력을 받으며 분산 통합 연산자는 컴퓨팅 구조체 연산자로부터 입력을 받습니다. 컴퓨팅 구조체 연산자는 Songs 테이블의 SongNameSongGenre 열에서 구조체를 만듭니다.

필터

필터 연산자는 입력에서 모든 행을 읽고 각 행에서 스칼라 조건자를 적용한 후 이 조건자를 충족하는 행만 반환합니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT s.LastName FROM (SELECT s.LastName
FROM Singers AS s LIMIT 3) s
WHERE s.LastName LIKE 'Rich%';

결과는 다음과 같습니다.

LastName
Richards

다음은 실행 계획입니다.

필터 연산자

성이 Rich로 시작하는 가수에 대한 조건자가 필터로 구현됩니다. 이 필터의 입력은 색인 스캔의 출력이고, 필터 출력은 LastNameRich로 시작하는 행입니다.

성능을 위해 필터가 스캔 위에 직접 위치할 때마다 필터는 데이터가 판독되는 방식에 영향을 줍니다. 예를 들어 키 k가 있는 테이블을 생각해보겠습니다. 테이블의 스캔 바로 위에 조건자 k = 5가 있는 필터는 전체 입력을 읽지 않고 k = 5와 일치하는 행을 찾습니다. 이렇게 하면 쿼리가 보다 효율적으로 실행됩니다. 위의 예시에서 필터 연산자는 WHERE s.LastName LIKE 'Rich%' 조건자를 충족하는 행만 읽습니다.

필터 스캔

필터 스캔 연산자는 항상 테이블 또는 색인 스캔의 맨 위에 있습니다. 이 연산자는 스캔을 사용하여 데이터베이스에서 읽은 행의 수를 줄이기 때문에 일반적으로 필터를 사용하는 경우보다 스캔이 더 빠릅니다. Spanner는 특정 조건에서 필터 스캔을 적용합니다.

  • 검색 가능한 조건: 검색 가능한 조건은 Spanner가 테이블에서 액세스할 특정 행을 결정할 수 있는 경우에 적용됩니다. 일반적으로는 필터가 기본 키의 프리픽스에 있는 경우가 이에 해당합니다. 예를 들어 기본 키가 Col1Col2로 구성된 경우, Col1, 또는 Col1Col2의 명시적 값을 포함하는 WHERE 절은 검색 가능합니다. 이 경우 Spanner는 키 범위 내에서만 데이터를 읽습니다.
  • 잔여 조건: 읽는 데이터의 양을 제한하기 위해 Spanner가 스캔을 평가할 수 있는 그 밖의 모든 조건입니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT LastName
FROM Singers
WHERE SingerId = 1

결과는 다음과 같습니다.

LastName
Richards

다음은 실행 계획입니다.

필터 스캔 연산자

한도

제한 연산자는 반환되는 행 수를 제한합니다. 선택사항인 OFFSET 매개변수는 반환할 시작 행을 지정합니다. 분산 시나리오의 경우, 제한 연산자를 로컬/전역 쌍으로 분리할 수 있습니다. 각 원격 서버는 출력 행에 대해 로컬 제한을 적용한 후 결과를 루트 서버에 반환합니다. 루트 서버는 원격 서버가 보낸 행을 집계한 후 전역 제한을 적용합니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT s.SongName
FROM Songs AS s
LIMIT 3;

결과는 다음과 같습니다.

SongName
Not About The Guitar
The Second Time
Starting Again

다음은 실행 계획입니다.

제한 연산자

로컬 제한은 각 원격 서버에 대한 제한입니다. 루트 서버는 원격 서버의 행을 집계한 후 전역 제한을 적용합니다.

임의 ID 할당

임의 ID 할당 연산자는 입력 행을 읽고 각 행에 임의의 숫자를 추가하여 출력을 생성합니다. Filter 또는 Sort 연산자와 함께 작동하여 샘플링 방법을 수행합니다. 지원되는 샘플링 방법으로는 BernoulliReservoir가 있습니다.

예를 들어 다음 쿼리에서는 샘플링 레이트가 10%인 Bernoulli 샘플링을 사용합니다.

SELECT s.SongName
FROM Songs AS s TABLESAMPLE BERNOULLI (10 PERCENT);

결과는 다음과 같습니다.

SongName
Starting Again
Nothing Is The Same

결과는 샘플이므로 쿼리가 동일해도 쿼리를 실행할 때마다 결과가 달라질 수 있습니다.

다음은 실행 계획입니다.

bernoulli 샘플 연산자

이 실행 계획에서 Random Id Assign 샘플 연산자는 분산 통합 연산자로부터 입력을 받으며 분산 통합 연산자는 색인 스캔 연산자로부터 입력을 받습니다. 연산자는 임의 ID가 있는 행을 반환하고 Filter 연산자는 임의 ID에 스칼라 조건자를 적용하고 행의 약 10%를 반환합니다.

다음 예시는 행 2개의 샘플링 레이트로 Reservoir 샘플링을 사용합니다.

SELECT s.SongName
FROM Songs AS s TABLESAMPLE RESERVOIR (2 ROWS);

결과는 다음과 같습니다.

SongName
I Knew You Were Magic
The Second Time

결과는 샘플이므로 쿼리가 동일해도 쿼리를 실행할 때마다 결과가 달라질 수 있습니다.

다음은 실행 계획입니다.

Reservoir 샘플 연산자

이 실행 계획에서 Random Id Assign 샘플 연산자는 분산 통합 연산자로부터 입력을 받으며 분산 통합 연산자는 색인 스캔 연산자로부터 입력을 받습니다. 연산자는 임의 ID가 있는 행을 반환하고 Sort 연산자는 임의 ID에 정렬 순서를 적용하고 2개의 행으로 LIMIT을 적용합니다.

결과 직렬화

결과 직렬화 연산자는 클라이언트에 반환하기 위해 쿼리의 최종 결과에 있는 각 행을 직렬화하는 컴퓨팅 구조체 연산자의 특수한 경우입니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT ARRAY(SELECT AS STRUCT so.SongName, so.SongGenre
             FROM Songs AS so
             WHERE so.SingerId = s.SingerId)
FROM Singers AS s;

이 쿼리는 SingerId를 기준으로 SongNameSongGenre로 구성된 배열을 요청합니다.

결과는 다음과 같습니다.

미지정
[]
[[Let's Get Back Together, COUNTRY], [Starting Again, ROCK]]
[[Not About The Guitar, BLUES]]
[]
[]

다음은 실행 계획입니다.

결과 직렬화 연산자

결과 직렬화 연산자는 Singers 테이블의 각 행에 대해 가수의 곡에 대한 SongNameSongGenre 쌍의 배열을 포함하는 결과를 만듭니다.

정렬

정렬 연산자는 입력 행을 읽고 열을 기준으로 이를 정렬한 후 정렬된 결과를 반환합니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT s.SongGenre
FROM Songs AS s
ORDER By SongGenre;

결과는 다음과 같습니다.

SongGenre
블루스
블루스
블루스
블루스
클래식
컨트리

다음은 실행 계획입니다.

정렬 연산자

이 실행 계획에서 정렬 연산자는 분산 통합 연산자로부터 입력 행을 받아 입력 행을 정렬하고 정렬된 행을 결과 직렬화 연산자로 반환합니다.

반환되는 행 수를 제한하기 위해 정렬 연산자는 선택적으로 LIMITOFFSET 매개변수를 사용할 수 있습니다. 분산 시나리오의 경우, LIMIT 또는 OFFSET 연산자가 있는 정렬 연산자는 로컬/전역 쌍으로 분리됩니다. 각 원격 서버는 입력 행에 대한 정렬 순서와 로컬 제한/오프셋을 적용한 후 결과를 루트 서버에 반환합니다. 루트 서버는 원격 서버가 보낸 행을 집계하고 정렬한 후 전역 제한/오프셋을 적용합니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT s.SongGenre
FROM Songs AS s
ORDER By SongGenre
LIMIT 3;

결과는 다음과 같습니다.

SongGenre
블루스
블루스
블루스

다음은 실행 계획입니다.

제한이 있는 정렬 연산자

실행 계획에는 원격 서버에 대한 로컬 제한과 루트 서버에 대한 전역 제한이 표시됩니다.

TVF

테이블 값 함수 연산자는 입력 행을 읽고 지정된 함수를 적용하여 출력을 생성합니다. 함수는 매핑을 구현하고 입력과 동일한 수의 행을 반환할 수 있습니다. 더 많은 행을 반환하는 생성자이거나 더 적은 행을 반환하는 필터일 수도 있습니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT Genre, SongName
FROM ML.PREDICT(MODEL GenreClassifier, Table Songs)

결과는 다음과 같습니다.

장르 SongName
컨트리 Not About The Guitar
The Second Time
Starting Again
Nothing Is The Same
컨트리 Let's Get Back Together
I Knew You Were Magic
일렉트릭 Blue
42
Fight Story

다음은 실행 계획입니다.

tvf 연산자

통합 입력

통합 입력 연산자는 결과를 전체 통합 연산자로 반환합니다. 실행 계획에서 통합 입력 연산자의 예시를 보려면 전체 통합 연산자를 참조하세요.

바이너리 연산자

바이너리 연산자는 2개의 관계형 하위 요소가 있는 연산자입니다. 다음 연산자는 바이너리 연산자입니다.

교차 적용

교차 적용 연산자는 다른 테이블의 쿼리로 검색된 각 행의 테이블 ​​쿼리를 실행하고 모든 테이블 쿼리 실행 통합을 반환합니다. 교차 적용 및 외부 적용 연산자는 해시 조인처럼 집합 기반 처리를 실행하는 연산자와는 달리 행 기반 처리를 실행합니다. 교차 적용 연산자에는 입력 등 2가지 입력이 있습니다. 교차 적용 연산자는 입력 측의 각 행을 맵 측에 적용합니다. 교차 적용 결과에는 입력 및 맵 측 모두의 열이 있습니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT si.FirstName,
  (SELECT so.SongName
   FROM Songs AS so
   WHERE so.SingerId=si.SingerId
   LIMIT 1)
FROM Singers AS si;

쿼리는 각 가수의 성과 가수의 곡 중 한 곡 이름만 요청합니다.

결과는 다음과 같습니다.

FirstName 미지정
Alice Not About The Guitar
Catalina Let's Get Back Together
David NULL
Lea NULL
Marc NULL

첫 번째 열에는 Singers 테이블의 내용이 채워지고 두 번째 열에는 Songs 테이블의 내용이 채워집니다. Singers 테이블에 SingerId 1개가 있지만 Songs 테이블에 일치하는 SingerId가 없으면 두 번째 열에 NULL이 포함됩니다.

다음은 실행 계획입니다.

교차 적용 연산자

최상위 노드는 분산 통합 연산자입니다. 분산 통합 연산자는 원격 서버에 하위 계획을 분배합니다. 이 하위 계획에는 가수의 성과 발표곡 중 한 곡의 이름을 컴퓨팅하고 출력의 각 행을 직렬화하는 결과 직렬화 연산자가 포함되어 있습니다.

결과 직렬화 연산자는 교차 적용 연산자에서 입력을 받습니다. 교차 적용 연산자의 입력 측은 Singers 테이블에 대한 테이블 스캔입니다.

교차 적용 연산의 맵 측에는 다음이 포함됩니다(위에서 아래로).

  • Songs.SongName을 반환하는 집계 연산자
  • 가수 1명당 반환되는 곡 수를 제한하는 제한 연산자
  • SongsBySingerAlbumSongNameDesc 색인에 대한 색인 스캔

교차 적용 연산자는 입력 측의 각 행을 동일한 SingerId를 가진 맵 측의 행에 매핑합니다. 교차 적용 연산자 출력은 입력 행의 FirstName 값과 맵 행의 SongName 값입니다. SingerId에 일치하는 맵 행이 없으면 SongName 값은 NULL이 됩니다. 그런 다음 실행 계획 맨 위에 있는 분산 통합 연산자가 원격 서버의 모든 출력 행을 결합하여 쿼리 결과로 반환합니다.

해시 조인

해시 조인 연산자는 해시에 기반해 SQL 조인을 구현한 것입니다. 해시 조인은 집합 기반 프로세싱을 실행합니다. 해시 조인 연산자는 빌드로 표시된 입력에서 행을 읽고 이를 조인 조건에 따라 해시 테이블에 삽입합니다. 그런 다음 해시 조인 연산자는 프로브로 표시된 입력에서 행을 읽습니다. 프로브 입력에서 읽는 각 행에 대해 해시 조인 연산자는 해시 테이블에서 일치하는 행을 찾습니다. 해시 조인 연산자는 일치하는 행을 결과로 반환합니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=hash_join} Songs AS s
ON a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId;

결과는 다음과 같습니다.

AlbumTitle SongName
Nothing To Do With Me Not About The Guitar
Green The Second Time
Green Starting Again
Green Nothing Is The Same
Green Let's Get Back Together
Green I Knew You Were Magic
Green Blue
Green 42
Terrified Fight Story

다음은 실행 계획입니다.

해시 조인 연산자

실행 계획에서 빌드Albums 테이블에 대한 스캔을 분산하는 분산 통합입니다. 프로브SongsBySingerAlbumSongNameDesc 색인에 대한 스캔을 분산하는 분산 통합 연산자입니다. 해시 조인 연산자는 빌드 측의 모든 행을 읽습니다. 각 빌드 행은 조건 a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId의 열을 기반으로 해시 테이블에 배치됩니다. 그런 다음 해시 조인 연산자는 프로브 측의 모든 행을 읽습니다. 각 스캔 행에 대해 해시 조인 연산자는 해시 테이블에서 일치하는 항목을 찾습니다. 일치 항목은 해시 조인 연산자에 의해 반환됩니다.

해시 테이블에서의 일치 결과는 반환되기 전에 나머지 조건으로 필터링될 수도 있습니다. (나머지 조건이 나타나는 부분의 예시는 비동등 조인에 있습니다.) 해시 조인 실행 계획은 메모리 관리 및 조인 변형으로 인해 복잡할 수 있습니다. 메인 해시 조인 알고리즘은 내부, 반, 반대, 외부 조인 변형을 처리하도록 조정됩니다.

병합 조인

병합 조인 연산자는 병합을 기반으로 구현한 SQL 조인입니다. 조인의 양측 모두 조인 조건에 사용된 열로 정렬된 행을 생성합니다. 병합 조인은 두 입력 스트림을 동시에 사용하고 조인 조건이 충족되었을 때 행을 출력합니다. 입력이 처음에 필요한 방식으로 정렬되지 않았으면 최적화 도구가 계획에 명시적인 Sort 연산자를 추가합니다.

병합 조인은 최적화 도구에서 자동으로 선택되지 않습니다. 이 연산자를 사용하려면 다음 예시에 표시된 것처럼 쿼리 힌트에서 조인 메서드를 MERGE_JOIN에 설정합니다.

SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=merge_join} Songs AS s
ON a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId;

결과는 다음과 같습니다.

AlbumTitle SongName
Green The Second Time
Green Starting Again
Green Nothing Is The Same
Green Let's Get Back Together
Green I Knew You Were Magic
Green Blue
Green 42
Terrified Fight Story
Nothing To Do With Me Not About The Guitar

다음은 실행 계획입니다.

병합 조인 연산자_1

이 실행 계획에서 병합 조인은 데이터가 있는 위치에서 조인이 실행되도록 분산됩니다. 또한 이 예시에서는 두 테이블 스캔이 조인 조건인 SingerId, AlbumId를 기준으로 이미 정렬되어 있으므로 추가 정렬 연산자 없이 이 예시에서 병합 조인을 사용할 수 있습니다. 이 계획에서는 Albums 테이블의 왼쪽 스캔은 SingerId, AlbumId가 오른쪽 SongsBySingerAlbumSongNameDesc 색인 스캔인 SingerId_1, AlbumId_1 쌍보다 상대적으로 작을 때 진행됩니다. 마찬가지로 오른쪽은 왼쪽보다 작을 때마다 오른쪽이 진행됩니다. 이 병합 진행은 결과 일치가 반환될 수 있도록 등가를 계속 검색합니다.

다음 쿼리를 사용하는 또 다른 병합 조인 예시를 살펴보세요.

SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=merge_join} Songs AS s
ON a.AlbumId = s.AlbumId;

결과는 다음과 같습니다.

AlbumTitle SongName
Total Junk The Second Time
Total Junk Starting Again
Total Junk Nothing Is The Same
Total Junk Let\'s Get Back Together
Total Junk I Knew You Were Magic
Total Junk Blue
Total Junk 42
Total Junk Not About The Guitar
Green The Second Time
Green Starting Again
Green Nothing Is The Same
Green Let\'s Get Back Together
Green I Knew You Were Magic
Green Blue
Green 42
Green Not About The Guitar
Nothing To Do With Me The Second Time
Nothing To Do With Me Starting Again
Nothing To Do With Me Nothing Is The Same
Nothing To Do With Me Let\'s Get Back Together
Nothing To Do With Me I Knew You Were Magic
Nothing To Do With Me Blue
Nothing To Do With Me 42
Nothing To Do With Me Not About The Guitar
Play The Second Time
Play Starting Again
Play Nothing Is The Same
Play Let\'s Get Back Together
Play I Knew You Were Magic
Play Blue
Play 42
Play Not About The Guitar
Terrified Fight Story

다음은 실행 계획입니다.

merge join operator_2

앞의 실행 계획에서 추가 Sort 연산자는 실행할 병합 조인에 필요한 속성을 얻기 위해 쿼리 최적화 도구로 도입되었습니다. 이 예시 쿼리에서 JOIN 조건은 AlbumId에만 있으며, 이것은 데이터 저장 방식이 아니므로, 정렬을 추가해야 합니다. 쿼리 엔진은 전역 대신 로컬로 정렬할 수 있게 해주는 분산 병합 알고리즘을 지원하여, CPU 비용을 분산 및 병렬화합니다.

결과 일치는 반환되기 전에 나머지 조건으로 필터링될 수도 있습니다. (나머지 조건이 나타나는 부분의 예시는 비동등 조인에 있습니다.) 추가 정렬 요구사항으로 인해 병합 조인 실행 계획이 복잡해질 수 있습니다. 메인 병합 조인 알고리즘은 내부, 반, 반대, 외부 조인 변형을 처리하도록 조정됩니다.

푸시 브로드캐스트 해시 조인

푸시 브로드캐스트 해시 조인 연산자는 분산 해시 조인을 기반으로 구현된 SQL 조인입니다. 푸시 브로드캐스트 해시 조인 연산자는 데이터 배치 생성을 위해 입력 측에서 행을 읽습니다. 그런 후 이 배치가 맵 측면 데이터를 포함하는 모든 서버에 브로드캐스트됩니다. 데이터 배치가 수신된 대상 서버에서 해시 조인은 배치를 빌드 측 데이터로 사용하여 빌드되고, 그런 후 로컬 데이터가 해시 조인의 프로브 측으로 스캔됩니다.

푸시 브로드캐스트 해시 조인은 최적화 도구에서 자동으로 선택되지 않습니다. 이 연산자를 사용하려면 다음 예시에 표시된 것처럼 쿼리 힌트에서 조인 메서드를 PUSH_BROADCAST_HASH_JOIN에 설정합니다.

SELECT a.AlbumTitle, s.SongName
FROM Albums AS a JOIN@{join_method=push_broadcast_hash_join} Songs AS s
ON a.SingerId = s.SingerId AND a.AlbumId = s.AlbumId;

결과는 다음과 같습니다.

AlbumTitle SongName
Green The Second Time
Green Starting Again
Green Nothing Is The Same
Green Lets Get Back Together
Green I Knew You Were Magic
Green Blue
Green 42
Terrified Fight Story
Nothing To Do With Me Not About The Guitar

다음은 실행 계획입니다.

push_broadcast hash_join 연산자

푸시 브로드캐스트 해시 조인에 대한 입력은 AlbumsByAlbumTitle 색인입니다. 이러한 입력은 데이터의 배치로 직렬화됩니다. 그런 후 이 배치가 SongsBySingerAlbumSongNameDesc 색인의 모든 로컬 분할로 전송됩니다. 여기서 배치는 역직렬화되고 해시 테이블로 빌드됩니다. 그런 후 해시 테이블은 로컬 색인 데이터를 프로브로 사용하여 결과 일치 항목을 반환합니다.

결과 일치는 반환되기 전에 나머지 조건으로 필터링될 수도 있습니다. (나머지 조건이 나타나는 부분의 예시는 비동등 조인에 있습니다.)

외부 적용

외부 적용 연산자는 필요할 경우 NULL로 채워진 행을 작성하여 맵 측의 각 실행이 행을 1개 이상 반환하도록 한다는 점만 제외하고는 교차 적용 연산자와 유사합니다. (즉, 왼쪽 외부 조인 의미를 제공합니다.)

N-항 연산자

N-항 연산자는 관계형 하위 요소가 2개 이상 있는 연산자입니다. 다음 연산자가 N-항 연산자입니다.

전체 통합

전체 통합 연산자는 중복을 제거하지 않고 하위 항목의 모든 행 집합을 결합합니다. 전체 통합 연산자는 여러 서버에 분산된 통합 입력 연산자로부터 입력을 받습니다. 전체 통합 연산자에는 동일한 스키마를 갖는 입력이 필요합니다. 즉, 각 열에 대해 동일한 데이터 유형 집합이 필요합니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT 1 a, 2 b
UNION ALL
SELECT 3 a, 4 b
UNION ALL
SELECT 5 a, 6 b;

하위 요소의 행 유형은 정수 2개로 구성됩니다.

결과는 다음과 같습니다.

a b
1 2
3 4
5 6

다음은 실행 계획입니다.

union_all_operator

전체 통합 연산자는 입력 행을 결합하며, 이 예시에서는 결과를 결과 직렬화 연산자로 보냅니다.

하위 요소가 열 이름에 대해 다른 변수를 사용하더라도 각 열에 동일한 데이터 유형 집합이 사용되므로, 다음과 같은 쿼리가 성공합니다.

SELECT 1 a, 2 b
UNION ALL
SELECT 3 c, 4 e;

하위 요소가 열에 다른 데이터 유형을 사용하므로, 다음과 같은 쿼리는 실패합니다.

SELECT 1 a, 2 b
UNION ALL
SELECT 3 a, 'This is a string' b;

스칼라 서브 쿼리

스칼라 서브 쿼리는 스칼라 표현식의 일부인 SQL 하위 표현식입니다. Spanner는 가능한 경우 항상 스칼라 서브 쿼리 제거를 시도합니다. 그러나 특정 시나리오에서는 계획에 스칼라 서브 쿼리가 명시적으로 포함될 수 있습니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT FirstName,
IF(FirstName='Alice',
   (SELECT COUNT(*)
    FROM Songs
    WHERE Duration > 300),
   0)
FROM Singers;

다음은 SQL 하위 표현식입니다.

SELECT COUNT(*)
FROM Songs
WHERE Duration > 300;

다음은 전체 쿼리 결과입니다.

FirstName
Alice 1
Catalina 0
David 0
Lea 0
Marc 0

다음은 실행 계획입니다.

스칼라 서브 쿼리 연산자

이 실행 계획은 집계 연산자 위에 Scalar Subquery로 표시된 스칼라 서브 쿼리를 포함합니다.

Spanner는 때로 스칼라 서브 쿼리를 조인 또는 교차 적용과 같은 다른 연산자로 변환하여 성능을 향상시킬 수 있습니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT *
FROM Songs
WHERE Duration = (SELECT MAX(Duration) FROM Songs);

다음은 SQL 하위 표현식입니다.

SELECT MAX(Duration) FROM Songs;

다음은 전체 쿼리 결과입니다.

SingerId AlbumId TrackId SongName 소요 시간 SongGenre
2 1 6 Nothing Is The Same 303 블루스

다음은 실행 계획입니다.

계획에 표시되지 않는 스칼라 서브 쿼리 연산자

Spanner가 스칼라 서브 쿼리를 교차 적용으로 변환했으므로, 실행 계획에는 스칼라 서브 쿼리가 포함되지 않습니다.

배열 서브 쿼리

배열 서브 쿼리는 스칼라 서브 쿼리와 비슷하지만 서브 쿼리가 입력 행을 2개 이상 사용할 수 있다는 점이 다릅니다. 소비된 행은 소비된 입력 행당 하나의 요소를 포함하는 단일 스칼라 출력 배열로 변환됩니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT a.AlbumId,
ARRAY(SELECT ConcertDate
      FROM Concerts
      WHERE Concerts.SingerId = a.SingerId)
FROM Albums AS a;

다음은 서브 쿼리입니다.

SELECT ConcertDate
FROM Concerts
WHERE Concerts.SingerId = a.SingerId;

AlbumId에 대한 서브 쿼리 결과가 해당 AlbumId에 대응한 ConcertDate 행 배열로 변환됩니다. 실행 계획에는 분산 통합 연산자 위에 Array Subquery로 표시된 배열 서브 쿼리가 포함됩니다.

배열 서브 쿼리 연산자

분산 연산자

이전에 이 페이지에서 설명된 연산자는 단일 머신 내에서 실행됩니다. 분산 연산자는 여러 서버에서 실행됩니다.

다음 연산자가 분산 연산자입니다.

분산 통합 연산자는 분산 교차 적용 및 분산 외부 적용을 파생시킨 기본 연산자입니다.

분산 연산자는 1개 이상의 로컬 분산 통합 변형 위에 분산 통합 변형을 사용하여 실행 계획에 나타납니다. 분산 통합 변형은 하위 계획의 원격 배포를 수행합니다. 이 실행 계획에 표시된 것처럼 로컬 분산 통합 변형은 쿼리에 대해 수행된 각 스캔 위에 있습니다.

분산 연산자

로컬 분산 통합 변형은 동적으로 변하는 분할 경계에 대해 재시작이 발생하는 경우 안정적인 쿼리 실행을 보장합니다.

가능한 경우 분산 통합 변형에는 분할 잘라내기를 유발하는 분할 조건자가 있습니다. 즉, 원격 서버는 조건자를 충족하는 분할에만 하위 계획을 실행합니다. 이렇게 하면 지연 시간과 전반적인 쿼리 성능이 향상됩니다.

분산 통합

분산 통합 연산자는 테이블 1개 이상을 개념적으로 여러 분할로 분할하고 각 분할에서 독립적으로 서브 쿼리를 원격 평가한 후 모든 결과를 통합합니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT s.SongName, s.SongGenre
FROM Songs AS s
WHERE s.SingerId = 2 AND s.SongGenre = 'ROCK';

결과는 다음과 같습니다.

SongName SongGenre
Starting Again
The Second Time
Fight Story

다음은 실행 계획입니다.

분산 통합 연산자

분산 통합 연산자는 분할 전체에서 테이블 스캔을 수행하는 원격 서버로 하위 계획을 보냅니다. 이때 분할은 쿼리의 조건자 WHERE s.SingerId = 2 AND s.SongGenre = 'ROCK'을 만족해야 합니다. 결과 직렬화 연산자는 테이블 스캔에서 반환된 행으로부터 SongNameSongGenre 값을 계산합니다. 그런 다음 분산 통합 연산자는 원격 서버에서 결합된 결과를 SQL 쿼리 결과로 반환합니다.

분산 병합 통합

분산 병합 통합 연산자는 여러 원격 서버에 쿼리를 분산합니다. 그런 다음 쿼리 결과를 결합하여 분산 병합 정렬이라고 하는 정렬된 결과를 생성합니다.

분산 병합 통합은 다음 단계를 실행합니다.

  1. 루트 서버는 쿼리된 데이터의 분할을 호스팅하는 각 원격 서버로 서브 쿼리를 보냅니다. 서브 쿼리에는 결과가 특정 순서로 정렬되는 지침이 포함됩니다.

  2. 각 원격 서버는 분할에서 서브 쿼리를 실행한 후 요청된 순서대로 결과를 다시 보냅니다.

  3. 루트 서버는 정렬된 서브 쿼리를 병합하여 완전히 정렬된 결과를 생성합니다.

분산 병합 통합은 Spanner 버전 3 이상에 기본적으로 사용 설정되어 있습니다.

분산 교차 적용

분산 교차 적용(DCA) 연산자는 교차 적용 연산자를 여러 서버에서 실행하여 확장합니다. DCA 입력 측은 행의 배치를 그룹화합니다(한 번에 입력 행 1개에서만 작업을 수행하는 일반 교차 적용 연산자와 다름). DCA 맵 측은 원격 서버에서 실행되는 교차 적용 연산자 조합입니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT AlbumTitle FROM Songs
JOIN Albums ON Albums.AlbumId=Songs.AlbumId;

결과는 다음과 같은 형식입니다.

AlbumTitle
Green
Nothing To Do With Me
Play
Total Junk
Green

다음은 실행 계획입니다.

분산 교차 적용 연산자

DCA 입력에는 AlbumId의 행을 일괄 처리하는 SongsBySingerAlbumSongNameDesc 색인에 대한 색인 스캔이 포함됩니다. 이 교차 적용 연산자의 맵 측은 AlbumsByAlbumTitle 색인에서 AlbumId 키와 일치하는 입력 행의 AlbumId 조건자를 조건으로 하는 색인 AlbumsByAlbumTitle의 색인 스캔입니다. 이 매핑으로 일괄 처리된 입력 행의 SingerId 값에 대한 SongName이 반환됩니다.

이 예시의 DCA 프로세스를 요약하면 DCA 입력은 Albums 테이블에서 일괄 처리된 행이고 DCA의 출력은 색인 스캔 맵에 이 행을 적용한 것입니다.

분산 외부 적용

분산 교차 적용 연산자가 교차 적용 연산자를 확장하는 것과 마찬가지로 분산 외부 적용 연산자는 외부 적용 연산자를 여러 서버에서 실행하여 확장합니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT LastName, ConcertDate FROM Singers
LEFT OUTER JOIN@{JOIN_TYPE=APPLY_JOIN} Concerts
ON Singers.SingerId=Concerts.SingerId;

결과는 다음과 같은 형식입니다.

LastName ConcertDate
Trentor 2014-02-18
Smith 2011-09-03
Smith 2010-06-06
Lomond 2005-04-30
Martin 2015-11-04
Richards

다음은 실행 계획입니다.

분산 외부 적용 연산자

변형 적용

변형 적용 연산자는 데이터 조작 언어(DML) 문의 변형을 테이블에 적용합니다. 이것은 DML 문의 쿼리 계획에서 최상위 연산자입니다.

예를 들어 다음 쿼리를 사용합니다.

DELETE FROM Singers
WHERE FirstName = 'Alice';

결과는 다음과 같습니다.

4 rows deleted
This statement deleted 4 rows and did not return any rows.

다음은 실행 계획입니다.

변형 적용 연산자

추가 정보

이 섹션은 독립 실행형 연산자는 아니지만 위에 나열한 연산자를 1개 이상 지원하는 태스크를 실행하는 항목에 대해 설명합니다. 여기에 설명된 항목은 기술적으로 연산자이지만 쿼리 계획에서 별도의 연산자로 구분되지 않습니다.

구조체 생성자

구조체 생성자구조체 또는 필드 컬렉션을 만듭니다. 일반적으로 컴퓨팅 연산의 결과인 행에 대한 구조체를 만듭니다. 구조체 생성자는 독립 실행형 연산자가 아닙니다. 대신, 컴퓨팅 구조체 연산자 또는 결과 직렬화 연산자에 나타납니다.

컴퓨팅 구조체 연산의 경우, 구조체 생성자는 계산된 행에 대한 열이 구조체에 대한 단일 변수 참조를 사용할 수 있도록 구조체를 생성합니다.

결과 직렬화 연산의 경우, 구조체 생성자는 결과를 직렬화하는 구조체를 만듭니다.

예를 들어 다음 쿼리를 사용합니다.

SELECT IF(TRUE, struct(1 AS A, 1 AS B), struct(2 AS A , 2 AS B)).A;

결과는 다음과 같습니다.

A
1

다음은 실행 계획입니다.

구조체 생성자

실행 계획에서 구조체 생성자는 결과 직렬화 연산자 안에 나타납니다.