프로젝션 쿼리

대부분의 Datastore 쿼리는 전체 항목을 결과로 반환하지만 실제로 애플리케이션이 관심을 갖는 항목의 속성은 몇 가지에 불과한 경우가 많습니다. 프로젝션 쿼리를 사용하면 실제로 필요한 항목의 특정 속성만 Datastore에 쿼리할 수 있으므로 전체 항목을 검색할 때보다 지연 시간과 비용이 낮아집니다.

프로젝션 쿼리는 SQL 쿼리 형식과 유사합니다.

SELECT name, email, phone FROM CUSTOMER

아래에 설명된 제한사항에 따라 표준 항목 쿼리에 사용할 수 있는 모든 필터링 및 정렬 기능을 사용할 수 있습니다. 쿼리는 지정된 속성(위 예시에서는 name, email, phone) 값만 채워진 요약된 결과를 반환하며 다른 모든 속성에는 데이터가 없습니다.

Go 1.11에서 프로젝션 쿼리 사용

Query를 준비 할 때 Project 메서드를 사용하여 프로젝션을 지정합니다.

q := datastore.NewQuery("People").Project("FirstName", "LastName")

결과를 반복하는 것과 같이 이러한 쿼리 결과를 표준 항목 쿼리처럼 처리합니다.

다음 예시는 DateWritten 기준으로 오름차순으로 정렬한 모든 EventLog 항목의 Title, ReadPath, DateWritten 속성에 대한 쿼리이며 각 속성의 값을 애플리케이션 로그에 작성합니다.

q := datastore.NewQuery("EventLog").
	Project("Title", "ReadPath", "DateWritten").
	Order("DateWritten")
t := q.Run(ctx)
for {
	var l EventLog
	_, err := t.Next(&l)
	if err == datastore.Done {
		break
	}
	if err != nil {
		log.Errorf(ctx, "Running query: %v", err)
		break
	}
	log.Infof(ctx, "Log record: %v, %v, %v", l.Title, l.ReadPath, l.DateWritten)
}

그룹화(실험용)

프로젝션 쿼리는 Distinct 메서드를 사용하여 완전히 고유한 결과만 결과 집합으로 반환되도록 할 수 있습니다. 그러면 프로젝션되는 속성 값이 동일한 항목의 첫 번째 결과만 반환됩니다.

q := datastore.NewQuery("Person").
	Project("LastName", "Height").Distinct().
	Filter("Height >", 20).
	Order("-Height").Order("LastName")

프로젝션 제한사항

프로젝션 쿼리에는 다음과 같은 제한사항이 적용됩니다.

  • 색인이 생성된 속성만 프로젝션할 수 있습니다.

    명시적이든 암묵적이든 관계없이 색인이 생성되지 않은 속성에 대해서는 프로젝션이 지원되지 않습니다. 1500바이트보다 긴 문자열과 1500개가 넘는 요소가 포함된 바이트 배열은 색인이 생성되지 않습니다.

  • 동일한 속성을 여러 번 프로젝션할 수 없습니다.

  • 일치(=) 필터에 참조된 속성을 프로젝션할 수 없습니다.

    예를 들면 다음과 같습니다.

    SELECT A FROM kind WHERE B = 1
    

    위의 쿼리에는 프로젝션된 속성이 일치 필터에 사용되지 않아 유효합니다.

    SELECT A FROM kind WHERE A > 1
    

    위의 쿼리에는 일치 필터가 사용되지 않았지만

    SELECT A FROM kind WHERE A = 1
    

    위의 쿼리는 프로젝션된 속성이 일치 필터에 사용되었으므로 유효하지 않습니다.

  • 프로젝션 쿼리에서 반환된 결과를 Datastore에 다시 저장할 수 없습니다.

    쿼리는 일부만 채워진 결과를 반환하므로 이 결과를 다시 Datastore에 쓰면 안 됩니다.

프로젝션 및 다중 값 속성

다중 값을 가진 속성을 프로젝션하면 해당 속성의 값이 일부만 채워집니다. 대신 쿼리와 일치하는 프로젝션된 값의 고유한 조합마다 별도의 항목이 반환됩니다. 예를 들어 종류가 Foo이고 두 개의 다중 값 속성 AB가 있는 항목이 있다고 가정해 보겠습니다.

entity := Foo{A: []int{1, 1, 2, 3}, B: []string{"x", "y", "x"}}

아래의 프로젝션 쿼리를 실행합니다.

q := datastore.NewQuery("Foo").Project("A", "B").Filter("A <", 3)

그러면 다음의 값 조합이 있는 4개 항목을 반환합니다.

A = 1, B = 'x'
A = 1, B = 'y'
A = 2, B = 'x'
A = 2, B = 'y'

항목에 값이 없는 다중 값 속성이 있는 경우, 항목이 색인에 포함되지 않고 해당 항목에 대한 결과가 해당 속성을 포함하는 프로젝션 쿼리에서 반환되지 않습니다.

프로젝션 색인

프로젝션 쿼리를 사용하려면 프로젝션에 지정된 모든 속성이 Datastore 색인에 포함되어야 합니다. App Engine 개발 서버는 애플리케이션과 함께 업로드되는 색인 구성 파일 index.yaml에서 필요한 색인을 자동으로 생성합니다.

필요한 색인 수를 최소화하는 한 가지 방법은 모든 속성이 항상 필요하지 않더라도 동일한 속성을 일관적으로 프로젝션하는 것입니다. 예를 들어 다음 쿼리에는 별도의 색인 두 개가 필요합니다.

SELECT A, B FROM Kind
SELECT A, B, C FROM Kind

그러나 항상 A, B, C 속성을 프로젝션하면 C가 필요하지 않는 경우에도 한 개의 색인만 필요합니다.

기존 쿼리를 프로젝션으로 변환하려면 프로젝션의 속성이 쿼리의 다른 부분에 이미 포함되어 있지 않은 경우 새 색인을 빌드해야 할 수도 있습니다. 예를 들어, 다음과 같은 기존 쿼리가 있다고 가정해 보겠습니다.

SELECT * FROM Kind WHERE A > 1 ORDER BY A, B

이 쿼리에는 다음과 같은 색인이 필요합니다.

Index(Kind, A, B)

이를 다음 프로젝션 쿼리 중 하나로 변환합니다.

SELECT C FROM Kind WHERE A > 1 ORDER BY A, B
SELECT A, B, C FROM Kind WHERE A > 1 ORDER BY A, B

그러면 새 속성(C)이 도입되어 새로운 색인 Index(Kind, A, B, C)를 생성해야 합니다. 아래의 프로젝션 쿼리를 실행합니다.

SELECT A, B FROM Kind WHERE A > 1 ORDER BY A, B

이 쿼리의 경우 프로젝션된 속성 AB가 이미 기존 쿼리에 포함되어 있기 때문에 필수 색인을 변경하지 않습니다.