쿼리 제한사항

이 페이지에서는 Google App Engine에서 Datastore를 쿼리할 때의 제한사항을 다룹니다. 다음 목록은 Datastore용으로 개발할 때 발생하는 일반적인 제한사항을 보여줍니다.

쿼리에서 명명된 속성이 없는 항목은 무시됨

동일한 종류의 항목이 반드시 동일한 속성을 가질 필요는 없습니다. 유효한 쿼리 결과를 얻으려면 항목에는 쿼리의 필터와 정렬 순서에 명명된 모든 속성에 값이 있어야 합니다(null 가능). 그렇지 않으면 쿼리를 실행하는 데 사용된 색인에서 항목이 생략되므로 쿼리 결과에 포함되지 않습니다.

색인이 생성되지 않은 속성을 필터링하면 결과가 반환되지 않음

쿼리는 색인이 생성되지 않은 속성 값을 찾을 수 없으며 그러한 속성을 정렬할 수도 없습니다. 색인이 생성되지 않은 속성에 대한 자세한 내용은 Datastore 색인 페이지를 참조하세요.

불일치 필터는 한 가지 속성 이하로 제한됨

전체 색인을 검색할 필요가 없도록 쿼리 메커니즘은 색인에서 서로 인접해 있는 모든 잠재적 쿼리 결과에 의존합니다. 이 제약 조건을 만족시키기 위해서는 단일 쿼리가 모든 필터에서 2개 이상의 속성에 대해 비균등 비교(LESS_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN, GREATER_THAN_OR_EQUAL, NOT_EQUAL)를 사용하지 못할 수 있습니다. 예를 들어 다음 쿼리는 두 불일치 필터가 동일한 속성에 적용되므로 유효합니다.

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter birthYearMaxFilter =
    new FilterPredicate("birthYear", FilterOperator.LESS_THAN_OR_EQUAL, maxBirthYear);

Filter birthYearRangeFilter =
    CompositeFilterOperator.and(birthYearMinFilter, birthYearMaxFilter);

Query q = new Query("Person").setFilter(birthYearRangeFilter);

그러나 이 쿼리는 서로 다른 두 속성에 불일치 필터를 사용하므로 유효하지 않습니다.

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter heightMaxFilter =
    new FilterPredicate("height", FilterOperator.LESS_THAN_OR_EQUAL, maxHeight);

Filter invalidFilter = CompositeFilterOperator.and(birthYearMinFilter, heightMaxFilter);

Query q = new Query("Person").setFilter(invalidFilter);

쿼리는 여러 속성에 대한 일치(EQUAL) 필터를 단일 속성에 대한 한 개 이상의 불일치 필터와 함께 사용할 수 있습니다. 따라서 다음 쿼리는 유효합니다.

Filter lastNameFilter = new FilterPredicate("lastName", FilterOperator.EQUAL, targetLastName);

Filter cityFilter = new FilterPredicate("city", FilterOperator.EQUAL, targetCity);

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Filter birthYearMaxFilter =
    new FilterPredicate("birthYear", FilterOperator.LESS_THAN_OR_EQUAL, maxBirthYear);

Filter validFilter =
    CompositeFilterOperator.and(
        lastNameFilter, cityFilter, birthYearMinFilter, birthYearMaxFilter);

Query q = new Query("Person").setFilter(validFilter);

정렬 순서를 지정하지 않으면 쿼리 결과의 순서가 정의되지 않음

쿼리에 정렬 순서가 지정되지 않으면 결과가 검색되는 순서대로 반환됩니다. Datastore 구현이 달라지거나 애플리케이션 색인이 변경되면 이 순서가 바뀔 수 있습니다. 따라서 애플리케이션에서 특정한 순서로 쿼리 결과가 필요하다면 정렬 순서를 쿼리에 명시적으로 지정해야 합니다.

속성에 일치 필터가 있으면 정렬 순서가 무시됨

쿼리는 지정된 속성에 일치 필터가 있으면 해당 속성에 지정된 모든 정렬 순서도 무시합니다. 그러면 모든 결과에서 속성의 값이 동일하고 더 이상 정렬할 필요가 없으므로 단일 값 속성의 불필요한 처리를 줄여 간단하게 최적화할 수 있습니다. 그러나 다중 값 속성은 일치 필터로 일치된 값 외에 다른 값도 가질 수 있습니다. 이러한 경우는 매우 드물 뿐 아니라 정렬 순서를 적용하려면 비용이 많이 들고 추가 색인이 필요하므로 Datastore 쿼리 플래너는 다중 값 속성의 경우에도 정렬 순서를 무시합니다. 따라서 지정된 정렬 순서와 다른 순서로 쿼리 결과가 반환될 수 있습니다.

불일치 필터에 사용되는 속성이 먼저 정렬되어야 함

불일치 필터와 일치하는 모든 결과를 검색하기 위해 쿼리는 필터와 일치하는 첫 번째 행을 색인에서 검색한 후 일치하지 않는 행이 나올 때까지 검색을 진행합니다. 전체 결과 집합을 연속된 행에 포함하려면 다른 속성보다 먼저 불일치 필터에 사용되는 속성에 따라 행이 정렬되어야 합니다. 따라서 쿼리에 하나 이상의 불일치 필터와 하나 이상의 정렬 순서가 함께 지정된 경우 첫 번째 정렬 순서는 불일치 필터에 지정된 속성을 참조해야 합니다. 다음 쿼리는 유효합니다.

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("birthYear", SortDirection.ASCENDING)
        .addSort("lastName", SortDirection.ASCENDING);

다음 쿼리는 불일치 필터에 사용되는 속성에 따라 정렬하지 않으므로 유효하지 않습니다.

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

// Not valid. Missing sort on birthYear.
Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("lastName", SortDirection.ASCENDING);

마찬가지로, 다음 쿼리는 불일치 필터에 사용되는 속성이 첫 번째로 정렬되는 속성이 아니므로 유효하지 않습니다.

Filter birthYearMinFilter =
    new FilterPredicate("birthYear", FilterOperator.GREATER_THAN_OR_EQUAL, minBirthYear);

// Not valid. Sort on birthYear needs to be first.
Query q =
    new Query("Person")
        .setFilter(birthYearMinFilter)
        .addSort("lastName", SortDirection.ASCENDING)
        .addSort("birthYear", SortDirection.ASCENDING);

다중 값 속성의 예기치 않은 동작

한 속성에 여러 값을 갖는 항목은 색인화 방식으로 인해 쿼리 필터 및 정렬 순서와 예기치 않은 의외의 방식으로 상호작용하는 경우가 있습니다.

쿼리에 지정된 속성의 비균등 필터가 여러 개 있으면 개별 속성 값 중 하나 이상이 모든 필터를 만족하는 경우에만 항목이 쿼리와 일치합니다. 예를 들어 항목 종류가 Widget이며 x 속성 값이 12라면 다음 쿼리와 일치하지 않습니다.

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.GREATER_THAN, 1),
                new FilterPredicate("x", FilterOperator.LESS_THAN, 2)));

항목의 각 x 값은 필터 중 하나를 만족하지만 두 필터를 모두 만족하는 값은 없습니다. 균등 필터에는 이 조건이 적용되지 않습니다. 예를 들어 동일한 항목이 쿼리를 만족합니다.

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.EQUAL, 1),
                new FilterPredicate("x", FilterOperator.EQUAL, 2)));

항목의 개별 x 값 중 어느 것도 두 필터 조건을 모두 만족하지 않지만 항목은 쿼리를 만족합니다.

NOT_EQUAL 연산자는 '값이 다음과 다름' 테스트로 작동합니다. 다음 쿼리 예를 참조하세요.

Query q = new Query("Widget").setFilter(new FilterPredicate("x", FilterOperator.NOT_EQUAL, 1));

위 쿼리는 x 값이 1과 다른 모든 Widget 항목과 일치합니다.

Java에서는 다음과 같은 쿼리를 사용할 수도 있습니다.

Query q =
    new Query("Widget")
        .setFilter(
            CompositeFilterOperator.and(
                new FilterPredicate("x", FilterOperator.NOT_EQUAL, 1),
                new FilterPredicate("x", FilterOperator.NOT_EQUAL, 2)));

위 쿼리는 다음과 같이 작동합니다.

x < 1 OR (x > 1 AND x < 2) OR x > 2

따라서 x 값이 1, 2, 3Widget 항목이 일치하지만 값이 12인 항목은 일치하지 않습니다.

마찬가지로 다중 값 속성의 정렬 순서는 일반적이지 않습니다. 이러한 속성은 고유한 값마다 색인에 한 번씩 나타나므로 색인에서 먼저 발견되는 값이 항목의 정렬 순서를 결정합니다.

  • 쿼리 결과가 오름차순으로 정렬된 경우, 속성에서 가장 작은 값이 순서 정렬에 사용됩니다.
  • 결과가 내림차순으로 정렬된 경우에는 가장 큰 값이 순서 정렬에 사용됩니다.
  • 다른 값은 정렬 순서에 영향을 주지 않으며, 값의 개수도 마찬가지입니다.

이로 인해 오름차순 내림차순 모두에서 속성 값이 19인 항목이 값이 4, 5, 6, 7인 항목보다 먼저 표시되는 비정상적인 결과가 발생합니다.

트랜잭션 내부의 쿼리에 상위 필터가 포함되어야 함

Datastore 트랜잭션은 동일한 항목 그룹에 속하는 항목(공통 상위 항목의 하위 항목)에서만 작동합니다. 이러한 제한사항을 준수하려면 트랜잭션 내에서 수행되는 모든 쿼리에는 트랜잭션의 다른 작업과 동일한 항목 그룹에 속하는 상위 항목을 지정하는 상위 필터가 포함되어야 합니다.