附註:我們強烈建議建構新應用程式的開發人員使用 NDB 用戶端程式庫,因為 NDB 用戶端程式庫與本用戶端程式庫相較之下有幾個優點,例如能透過 Memcache API 自動將實體加入快取。如果您目前使用的是舊版的 DB 用戶端程式庫,請參閱從 DB 至 NDB 的遷移指南。
大多數 Datastore 查詢結果會傳回完整實體,但應用程式真正需要的往往只有該實體的幾項屬性。您可以按照實際需求,運用「投影查詢」在 Datastore 中單純查詢某個實體的特定屬性,相較於擷取完整實體,這種方式更有助於減少延遲時間及降低費用。
投影查詢近似於下列形式的 SQL 查詢:
SELECT name, email, phone FROM CUSTOMER
您可以使用所有適用於查詢標準實體的篩選及排序功能,但必須遵守以下說明的幾項限制。查詢會傳回只包含指定屬性的簡略版結果 (以此範例來說就是 name
、email
和 phone
),且這些屬性均已填入值;其他所有屬性均沒有資料。
在 Python 2 中使用投影查詢
指定投影的方式如下:Query 和 GqlQuery 物件皆支援投影查詢。這兩種類別都要求進行這項匯入作業:
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
項目的 title
、read_path
和 date_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
種類的實體,包含兩個多值屬性 A
和 B
:
之後,投影查詢
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
不過,如果一律投影 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
「不會」變更需要的索引,因為現有查詢中已包含投影屬性 A
和 B
。