投影查詢

附註:我們強烈建議建構新應用程式的開發人員使用 NDB 用戶端程式庫,因為 NDB 用戶端程式庫與本用戶端程式庫相較之下有幾個優點,例如能透過 Memcache API 自動將實體加入快取。如果您目前使用的是舊版的 DB 用戶端程式庫,請參閱從 DB 至 NDB 的遷移指南

大多數 Datastore 查詢結果會傳回完整實體,但應用程式真正需要的往往只有該實體的幾項屬性。您可以按照實際需求,運用「投影查詢」在 Datastore 中單純查詢某個實體的特定屬性,相較於擷取完整實體,這種方式更有助於減少延遲時間及降低費用。

投影查詢近似於下列形式的 SQL 查詢:

SELECT name, email, phone FROM CUSTOMER

您可以使用所有適用於查詢標準實體的篩選及排序功能,但必須遵守以下說明的幾項限制。查詢會傳回只包含指定屬性的簡略版結果 (以此範例來說就是 nameemailphone),且這些屬性均已填入值;其他所有屬性均沒有資料。

在 Python 2 中使用投影查詢

指定投影的方式如下:QueryGqlQuery 物件皆支援投影查詢。這兩種類別都要求進行這項匯入作業:

from google.appengine.ext import db

指定投影的方式如下:

proj = db.Query(entity_name, projection=('property_1', 'property_2','property_n'))

proj = db.GqlQuery("SELECT property_1, property_2, property_n FROM entity_name")

處理這些查詢結果的方式與處理標準實體查詢結果的方式相同。舉例來說,您可以疊代處理結果。

以下範例會查詢所有 EventLog 項目的 titleread_pathdate_written 屬性,並依 date_written 的遞增順序排序,然後將每個屬性的值寫入應用程式記錄:

for proj in db.GqlQuery("SELECT title, read_path, date_written" +
                        "FROM EventLog" +
                        "ORDER BY date_written ASC"):
  logging.info(proj.title)
  logging.info(proj.read_path)
  logging.info(proj.date_written)

分組(實驗版)

投影查詢可以使用 distinct 關鍵字,確認結果集只傳回完全不重複的結果。如有多個實體的投影屬性包含相同的值,這種方式只會傳回第一個結果。

query = db.Query(projection=['A', 'B'], distinct=True).filter('B >', 1).order('-B, A')

投影限制

投影查詢必須遵循以下限制:

  • 只能投影已建立索引的屬性。

    未建立索引的屬性不支援投影功能 (不分明確或隱含)。長文字字串 (Text) 和長位元組字串 (Blob) 不會建立索引。

  • 不能重複投影同一個屬性。

  • 不能投影等式 (=) 或成員資格 (IN) 篩選器所參照的屬性。

    例如,假設使用者要求系統 將文字從英文翻譯成法文

    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=[1, 1, 2, 3], B=['x', 'y', 'x'])

之後,投影查詢

SELECT A, B FROM Foo WHERE A < 3

會傳回四個包含下列組合值的實體:

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

不過,如果一律投影 ABC 等屬性 (即使是在不需要 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