O Google Code é oferecido em: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
Cada consulta ao armazenamento de dados utiliza um índice, uma tabela que contém os resultados da consulta na ordem desejada. Um aplicativo do Google App Engine define seus índices em um arquivo de configuração denominado index.yaml. O servidor da web para desenvolvimento adiciona sugestões a este arquivo automaticamente, ao encontrar consultas que ainda não têm índices configurados. Você pode ajustar os índices manualmente, editando o arquivo antes de enviar o aplicativo.
O mecanismo de consulta baseado em índice suporta a maioria dos tipos de consulta comuns, mas não suporta alguns tipos de consulta que você pode ter o costume de fazer em outras tecnologias de bancos de dados. As restrições de consultas e suas explicações são descritas abaixo.
Uma consulta recupera entidades do armazenamento de dados que atendam a um conjunto de condições. A consulta especifica um tipo de entidade, zero ou mais condições com base em valores de propriedade de entidade (às vezes denominados "filtros") e zero ou mais descrições de ordem de classificação. Quando a consulta é executada, ela obtém todas as entidades de um tipo determinado que atendam a todas as condições dadas, classificadas na ordem descrita.
A API de armazenamento de dados em Python fornece duas interfaces para a preparação e execução de consultas: a interface Query, que utiliza métodos para preparar a consulta, e a interface GqlQuery, que utiliza uma linguagem semelhante à SQL, denominada GQL, para preparar a consulta a partir de uma string de consulta. Essas interfaces são descritas com mais detalhes em Criação, obtenção e exclusão de dados: Como obter entidades utilizando uma consulta e nas páginas de referência correspondentes.
class Person(db.Model):
first_name = db.StringProperty()
last_name = db.StringProperty()
city = db.StringProperty()
birth_year = db.IntegerProperty()
height = db.IntegerProperty()
# The Query interface prepares a query using instance methods.
q = Person.all()
q.filter("last_name =", "Smith")
q.filter("height <", 72)
q.order("-height")
# The GqlQuery interface prepares a query using a GQL query string.
q = db.GqlQuery("SELECT * FROM Person " +
"WHERE last_name = :1 AND height < :2 " +
"ORDER BY height DESC",
"Smith", 72)
# The query is not executed until results are accessed.
results = q.fetch(5)
for p in results:
print "%s %s, %d inches tall" % (p.first_name, p.last_name, p.height)
Um filtro inclui um nome de propriedade, um operador de comparação e um valor. Uma entidade passa o filtro se tiver uma propriedade do nome fornecido e o seu valor se compara ao valor fornecido como descrito pelo operador. A entidade será um resultado da consulta se ela passar por todos os seus filtros.
O operador do filtro pode ser qualquer um destes:
< menor que<= menor ou igual a= igual a> maior que>= maior ou igual a!= diferente deIN igual a qualquer um dos valores da lista fornecidaNa verdade, o operador != realiza duas consultas: uma em que todos os outros filtros são os mesmos e o filtro diferente é substituído por um filtro "menor que", e outra em que o filtro diferente é substituído por um filtro "maior que". Os resultados são mesclados, em ordem. Como descrito abaixo, na discussão sobre filtros de desigualdade, uma consulta pode ter apenas um filtro diferente e não pode ter outros filtros de desigualdade.
O operador IN também realiza várias consultas, uma para cada item no valor da lista fornecida em que todos os outros filtros são o mesmo e o filtro IN é substituído por um filtro "igual-a". Os resultados são mesclados, na ordem dos itens na lista. Se uma consulta tem filtros além de IN, a consulta é realizada como vária consultas, uma para cada combinação de valores nos filtros IN.
Uma única consulta contendo os operadores != e IN está limitada a 30 subconsultas.
O armazenamento de dados do Google App Engine mantém um índice para cada consulta que um aplicativo pretende realizar. À medida que o aplicativo faz alterações nas entidades do armazenamento de dados, este atualiza os índices com os resultados corretos. Quando o aplicativo executa uma consulta, o armazenamento de dados obtém os resultados diretamente do índice correspondente.
Um aplicativo tem um índice para cada combinação de tipo, propriedade de filtro e operador, e ordem de classificação usados em uma consulta. Considere o exemplo de consulta, declarada em GQL:
SELECT * FROM Person WHERE last_name = "Smith"
AND height < 72
ORDER BY height DESC
O índice desta consulta é uma tabela de chaves de entidades do tipo Person, com colunas para os valores das propriedades height e last_name. O índice é classificado por height em ordem decrescente.
Duas consultas do mesmo formulário mas com valores de filtros diferentes utilizam o mesmo índice. Por exemplo, a consulta abaixo utiliza o mesmo índice que a consulta acima:
SELECT * FROM Person WHERE last_name = "Jones"
AND height < 63
ORDER BY height DESC
O armazenamento de dados executa uma consulta utilizando as etapas abaixo:
Uma tabela de índice contém colunas para cada propriedade usada em um filtro ou ordem de classificação. As linhas são classificadas pelos aspectos abaixo, em ordem:
Observação: Para as finalidades dos índices, os filtros IN são manipulados como filtros = e os filtros != são manipulados como os outros filtros de desigualdade.
Isso coloca todos os resultados de cada consulta possível que utilize este índice em linhas consecutivas da tabela.
Dica: Os filtros de consulta não têm uma maneira explícita de comparar apenas parte do valor de uma string, mas você pode realizar uma falsa correspondência de prefixo usando os filtros de desigualdade:
db.GqlQuery("SELECT * FROM MyModel WHERE prop >= :1 AND prop < :2", "abc", u"abc" + u"\ufffd")
Isso faz a correspondência de todas as entidades MyModel com uma propriedade de string prop iniciada pelos caracteres abc. A string de unicode u"\ufffd" representa o maior caractere Unicode possível. Quando os valores de propriedade são classificados em um índice, os valores deste intervalo são todos aqueles iniciados pelo prefixo dado.
Esse mecanismo suporta uma ampla variedade de consultas e é adequado para a maioria dos aplicativos. Entretanto, ele não suporta alguns tipos de consultas que você pode ter o costume de fazer em outras tecnologias de banco de dados.
Um índice contém somente as entidades que tiverem todas as propriedades mencionadas no índice. Se uma entidade não tiver uma propriedade mencionada em um índice, a entidade não aparecerá no índice e nunca será um resultado da consulta que utiliza o índice.
O armazenamento de dados do Google App Engine diferencia uma entidade que não possui uma propriedade de uma entidade que possui a propriedade com um valor nulo (None). Se você quiser que toda entidade de um certo tipo seja um possível resultado para uma consulta, poderá usar um modelo de dados que atribui um valor padrão (como None) às propriedades usadas pelos filtros da consulta.
Propriedades com valores do tipo de valor de texto longo (Text) ou do tipo de valor de binário longo (Blob) não são incluídos nos índices e, por isso, não podem ser encontrados pelas consultas.
Como consequência da não indexação desses valores de propriedade, uma consulta com filtro ou ordem de classificação de uma propriedade nunca encontrará uma entidade cujo valor da propriedade seja Text ou Blob. As propriedades com tais valores comportam-se como se a propriedade não fosse definida em relação aos filtros de consulta e ordens de classificação.
Quando duas entidades têm propriedades com o mesmo nome, mas com tipos de valores diferentes, um índice da propriedade classifica as entidades primeiro pelo tipo do valor e depois pela ordem apropriada ao tipo. Por exemplo, se duas entidades cada tiverem uma propriedade chamada "idade", uma com um valor de número inteiro e outra com um valor de string, a entidade com o valor de número inteiro sempre aparecerá antes da entidade com o valor de string quando forem classificadas pela propriedade "Idade", independentemente dos valores em si.
É importante observar isso, especialmente no caso de números inteiros e números de ponto flutuante, que são tratados como tipos separados pelo armazenamento de dados. Uma propriedade com o valor de número inteiro 38 é classificada antes de uma propriedade com o valor de ponto flutuante 37.5, pois todos os inteiros são classificados antes dos flutuantes.
Como padrão, o Google App Engine constrói índices para diversas consultas simples. Para outras consultas, o aplicativo deve especificar os índices de que necessita em um arquivo de configuração denominado index.yaml. Se o aplicativo sendo executado no Google App Engine tentar realizar uma consulta para a qual não exista um índice correspondente (fornecido como padrão ou descrito em index.yaml), a consulta irá falhar.
O Google App Engine fornece índices automáticos para os seguintes formulários de consulta:
Para outros formulários de consulta, é necessário especificar o índice em index.yaml, incluindo:
O servidor da web para desenvolvimento facilita o gerenciamento da configuração de índice: em vez de não executar uma consulta que exige um índice, mas não o tem, o servidor da web para desenvolvimento pode gerar a configuração de um índice que permitiria o êxito da consulta. Se os testes locais do seu aplicativo chamarem todas as consultas possíveis que o aplicativo irá fazer (cada combinação de tipo, ancestral, filtro e ordem de classificação), as entradas geradas representarão um conjunto completo de índices. Se os seus testes não exercitarem todos os formulários de consulta possíveis, você poderá verificar e ajustar a configuração do índice antes de enviar o aplicativo.
Como padrão, o Google App Engine constrói índices para diversas consultas simples. Para outras consultas, o aplicativo deve especificar os índices de que necessita em um arquivo de configuração denominado index.yaml. Se o aplicativo sendo executado no Google App Engine tentar realizar uma consulta para a qual não exista um índice correspondente (fornecido como padrão ou descrito em index.yaml), a consulta irá falhar.
index.yaml descreve cada tabela de índice, incluindo o tipo, necessárias às propriedades para os filtros e ordens de classificação de consulta e se a consulta utiliza ou não uma cláusula de ancestral (uma cláusula Query.ancestor() ou ANCESTOR IS de GQL). As propriedades são listadas na ordem em que serão classificadas: propriedades usadas em filtros de igualdade ou IN primeiro, seguidas pela propriedade usada em filtros de desigualdade e por fim as ordens de classificação dos resultados da consulta e suas direções.
Veja novamente o exemplo de consulta abaixo:
SELECT * FROM Person WHERE last_name = "Smith"
AND height < 72
ORDER BY height DESC
Se o aplicativo executou somente esta consulta (e possivelmente outras consultas semelhantes a esta, mas com valores diferentes para "Smith" e 72), o arquivo index.yaml teria a seguinte aparência:
indexes:
- kind: Person
properties:
- name: last_name
- name: height
direction: desc
Quando uma entidade é criada ou atualizada, cada índice apropriado também é atualizado. O número de índices que se aplicam a uma entidade afeta o tempo gasto para criar ou atualizar a entidade.
Para obter mais informações sobre a sintaxe de index.yaml, consulte Configuração de índices.
As chaves de entidade podem ser o assunto de um filtro de consulta ou de uma ordem de classificação, usando o nome especial __key__ no lugar do nome da propriedade. O armazenamento de dados considera o valor da chave completa para essas consultas, incluindo o caminho do pai, o tipo e a string com o nome da chave atribuído pelo aplicativo ou um ID numérico atribuído pelo sistema da entidade.
Como uma chave de entidade é exclusiva em todas as entidades no sistema, as consultas __key__facilitam a recuperação em lote de entidades de um determinado tipo, como para um depósito de lote do conteúdo do armazenamento de dados. Diferentemente de offset, isso funciona de maneira eficaz em qualquer número de entidades. Por exemplo:
class MainHandler(webapp.RequestHandler):
def get(self):
query = Entity.gql('ORDER BY __key__')
# Use a query parameter to keep track of the last key of the last
# batch, to know where to start the next batch.
last_key_str = self.request.get('last')
if last_key_str:
last_key = db.Key(last_key_str)
query = Entity.gql('WHERE __key__ > :1 ORDER BY __key__', last_key)
# For batches of 20, fetch 21, then use result #20 as the "last"
# if there is a 21st.
entities = query.fetch(21)
new_last_key_str = None
if len(entities) == 21:
new_last_key_str = str(entities[19].key())
# Return the data and new_last_key_str. Client would use
# http://...?last=new_last_key_str to fetch the next batch.
# ...
As chaves são classificadas primeiro pelo caminho pai, em seguida pelo tipo e, por fim, pelo nome de chave ou ID. Os tipos e nomes de chave são strings e são classificados pelo valor de byte. IDs são números inteiros e são classificados numericamente. Se entidades com o mesmo pai e tipo usarem uma mistura de strings de nome de chave e IDs numéricos, as entidades com IDs numéricos serão consideradas inferiores às entidades com strings de nome de chave. Os elementos do caminho pai são comparados de forma parecida: pelo tipo (string) e depois pelo nome de chave (string) ou ID (número).
As consultas que envolvem chaves usam índices da mesma forma que as consultas que envolvem propriedades, com uma pequena diferença: ao contrário do que ocorre com uma propriedade, uma consulta com um filtro de igualdade na chave que também tem filtros adicionais deve usar um índice personalizado definido no arquivo de configuração de índice do aplicativo. Assim como faz com todas as consultas, o servidor da web para desenvolvimento cria entradas de configuração apropriadas nesse arquivo quando uma consulta que precisa de um índice personalizado é testada.
A natureza do mecanismo de consulta do índice impõe algumas restrições sobre o que uma consulta pode fazer.
Uma condição de filtro de consulta ou ordem de classificação para uma propriedade também implica a condição de que a entidade tenha um valor para a propriedade.
Uma entidade do armazenamento de dados não precisa ter um valor para uma propriedade presente em outras entidades do mesmo tipo. Um filtro de uma propriedade irá comparar somente a entidade que tiver um valor para a propriedade. As entidades que não tiverem um valor para uma propriedade usada em um filtro ou ordem de classificação são omitidas do índice gerado para a consulta.
Não é possível realizar uma consulta por entidades que não tenham uma determinada propriedade. Uma alternativa é criar uma propriedade fixa (modelada) com valor padrão de None e criar um filtro para entidades com None como o valor da propriedade.
Uma consulta somente pode usar os filtros de desigualdade (<, <=, >=, >, !=) em uma propriedade.
Por exemplo, esta consulta é permitida:
SELECT * FROM Person WHERE birth_year >= :min
AND birth_year <= :max
Entretanto, esta consulta não é permitida, porque utiliza filtros de desigualdade em duas propriedades diferentes na mesma consulta:
SELECT * FROM Person WHERE birth_year >= :min_year
AND height >= :min_height # ERROR
Os filtros podem combinar comparações de igualdade (=) para diferentes propriedades na mesma consulta, incluindo consultas com uma ou mais condições de desigualdade em uma propriedade. Isto é permitido:
SELECT * FROM Person WHERE last_name = :last_name
AND city = :city
AND birth_year >= :min_year
O mecanismo de consulta depende de todos os resultados de uma consulta serem adjacentes na tabela de índice, para evitar percorrer a tabela inteira em busca de resultados. Uma única tabela de índice não pode representar diversos filtros de desigualdade em diversas propriedades e manter todos os resultados de forma consecutiva na tabela.
Se uma consulta tiver um filtro com uma comparação de desigualdade e uma ou mais ordens de classificação, ela deve incluir uma ordem de classificação para a propriedade usada na desigualdade e a ordem de classificação deve aparecer antes das ordens das outras propriedades.
Esta consulta não é válida, pois utiliza um filtro de desigualdade e não classifica segundo a propriedade filtrada:
SELECT * FROM Person WHERE birth_year >= :min_year
ORDER BY last_name # ERROR
De modo semelhante, esta consulta não é válida, pois não classifica segundo a propriedade filtrada antes de classificar pelas outras propriedades:
SELECT * FROM Person WHERE birth_year >= :min_year
ORDER BY last_name, birth_year # ERROR
Esta consulta é válida:
SELECT * FROM Person WHERE birth_year >= :min_year
ORDER BY birth_year, last_name
Para obter todos os resultados que correspondam a um filtro de desigualdade, uma consulta percorre a tabela de índice até encontrar a primeira linha correspondente e retorna todos os resultados consecutivos até encontrar uma linha que não corresponda. Para que as linhas consecutivas representem o conjunto completo de resultados, elas devem ser classificadas pelo filtro de desigualdade antes das outras ordens de classificação.
Devido à maneira com a qual as propriedades com múltiplos valores são indexadas, a ordem de classificação dessas propriedades é incomum:
Esta ordem de classificação tem a conseqüência incomum de fazer [1, 9] vir antes de [4, 5, 6, 7] nas ordens crescente e decrescente.
É importante lembrar das consultas com filtro de igualdade e ordem de classificação em uma propriedade com múltiplos valores. Nessas consultas, a ordem de classificação é ignorada. Para as propriedades com valores únicos, esta é uma simples otimização. Todos os resultados teriam o mesmo valor para a propriedade, não sendo necessário classificá-los.
Entretanto, as propriedades com múltiplos valores podem ter valores adicionais. Como a ordem de classificação é ignorada, os resultados da consulta podem ser retornados em uma ordem diferente do que se a ordem de classificação fosse aplicada. (Restaurar a ordem de classificação ignorada poderia ser dispendioso e exigir índices extra. Como este caso de uso é raro, ele é deixado de lado pelo planejador de consultas).
Como foi descrito acima, cada propriedade (que não tenha um valor Text ou Blob) de cada entidade é adicionada a pelo menos uma tabela de índice, incluindo um índice simples fornecido por padrão e qualquer outro índice descrito no arquivo do aplicativo index.yaml que menciona a propriedade. Para que uma entidade tenha um valor para cada propriedade, o Google App Engine armazena um valor de propriedade uma única vez em seu índice simples e uma vez para cada vez que a propriedade é mencionada em um índice personalizado. Cada uma dessas entradas de índice deve ser atualizada sempre que o valor da propriedade for alterado. Assim, quanto mais índices fizerem referência à propriedade, mais tempo será necessário para atualizar a propriedade.
Para evitar que a atualização de uma entidade demore muito, o armazenamento de dados limita o número de entradas de índice que podem existir para uma única propriedade. O limite é grande e a maioria dos aplicativos sequer irá notar. Entretanto, você pode atingir o limite em algumas circunstâncias. Por exemplo, uma entidade com muitas propriedades de valor único pode exceder o limite de entradas de índice.
As propriedades com múltiplos valores armazenam cada valor como uma entrada separada em um índice. Uma entidade com uma única propriedade com muitos valores pode exceder o limite de entradas de índice.
Os índices personalizados que fazem referência a diversas propriedades com diversos valores podem ficar muito grandes com apenas alguns valores. Para registrar completamente essas propriedades, a tabela de índice deve incluir uma linha para cada permutação dos valores de cada propriedade do índice.
Por exemplo, o índice a seguir (descrito em sintaxe index.yaml) inclui as propriedades x e y para entidades do tipo MyModel:
indexes: - kind: MyModel properties: - name: x - name: y
O código a seguir cria uma entidade com dois valores para a propriedade x e dois valores para a propriedade y:
class MyModel(db.Expando): pass e2 = MyModel() e2.x = ['red', 'blue'] e2.y = [1, 2] e2.put()
Para representar esses valores com exatidão, o índice deve armazenar 12 valores de propriedade: dois de cada para os índices embutidos em x e y e dois para cada uma das quatro permutações de x e y no índice personalizado. Com muitos valores de propriedades de múltiplos valores, isto pode significar que um índice precisa armazenar muitas entradas de índice para uma única entidade. Um índice que faz referência a diversas propriedades com diversos valores pode ser chamado de "índice explosivo", pois pode tornar-se muito grande com apenas alguns valores.
Se um put() resultar em um número de entradas de índice que exceda o limite, a chamada falhará com uma exceção. Se você criar um índice novo em que algumas das entradas de índice excedam o limite de qualquer entidade quando gerado, as consultas realizadas ao índice falharão e este aparecerá em estado de "Erro" no Console administrativo.
Para lidar com índices em "Erro", primeiro remova-os de seu arquivo index.yaml e execute appcfg.py vacuum_indexes. Em seguida, reformule a definição do índice e as consultas correspondentes ou remova as entidades que estão fazendo o índice "explodir". Finalmente, adicione o índice a index.yaml novamente e execute appcfg.py update_indexes.
Para evitar os índices explosivos, evite consultas que exijam o uso de uma propriedade de lista em um índice personalizado. Conforme descrito acima, isso inclui consultas com diversas ordens de classificação, uma mistura de filtros de igualdade e desigualdade e filtros de ancestral.