Melhores práticas para Coleções de séries temporais
Nesta página
- Otimizar inserções
- Gravações de documentos em lote
- Usar ordem de campo consistente em documentos
- Aumentar o número de clientes
- Otimizar compressão
- Campos de omissão contendo objetos vazios e arrays de documentos
- Arredondar dados numéricos para poucos locais decimais
- Otimizar o desempenho da consulta
- Definir a granularidade apropriada do bucket
- Criar índices secundários
- Query de metaFields em subcampos
- Use $group em vez de Distinct()
Esta página descreve as melhores práticas para melhorar o desempenho e o uso de dados para coleções de séries temporais.
Otimizar inserções
Para otimizar o desempenho de inserção para coleções de séries temporais, execute as seguintes ações.
Gravações de documentos em lote
Ao inserir vários documentos:
Para evitar idas e vindas da rede, use uma única instrução
insertMany()
em vez de várias instruçõesinsertOne()
.Se possível, construa lotes para conter múltiplas medições por série (conforme definido pelos metadados).
Para melhorar o desempenho, defina o parâmetro
ordered
parafalse
.
Por exemplo, se você tiver dois sensores, sensor A
e sensor B
, um lote contendo múltiplas medições de um único sensor incorrerá no custo de uma inserção, em vez de uma inserção por medida.
A operação a seguir insere seis documentos, mas só incorre no custo de duas inserções (uma por lote), pois os documentos são ordenados por sensor. O parâmetro ordered
está configurado para false
para melhorar o desempenho:
db.temperatures.insertMany( [ { "metadata": { "sensor": "sensorA" }, "timestamp": ISODate("2021-05-18T00:00:00.000Z"), "temperature": 10 }, { "metadata": { "sensor": "sensorA" }, "timestamp": ISODate("2021-05-19T00:00:00.000Z"), "temperature": 12 }, { "metadata": { "sensor": "sensorA" }, "timestamp": ISODate("2021-05-20T00:00:00.000Z"), "temperature": 13 }, { "metadata": { "sensor": "sensorB" }, "timestamp": ISODate("2021-05-18T00:00:00.000Z"), "temperature": 20 }, { "metadata": { "sensor": "sensorB" }, "timestamp": ISODate("2021-05-19T00:00:00.000Z"), "temperature": 25 }, { "metadata": { "sensor": "sensorB" }, "timestamp": ISODate("2021-05-20T00:00:00.000Z"), "temperature": 26 } ], { "ordered": false })
Usar ordem de campo consistente em documentos
Usar uma ordem de campo consistente em seus documentos melhora o desempenho da inserção.
Por exemplo, a inserção destes documentos proporciona um desempenho de inserção ideal:
{ "_id": ObjectId("6250a0ef02a1877734a9df57"), "timestamp": ISODate("2020-01-23T00:00:00.441Z"), "name": "sensor1", "range": 1 }, { "_id": ObjectId("6560a0ef02a1877734a9df66"), "timestamp": ISODate("2020-01-23T01:00:00.441Z"), "name": "sensor1", "range": 5 }
Por outro lado, esses documentos não alcançam o desempenho ideal de inserção, porque suas ordens de campo diferem:
{ "range": 1, "_id": ObjectId("6250a0ef02a1877734a9df57"), "name": "sensor1", "timestamp": ISODate("2020-01-23T00:00:00.441Z") }, { "_id": ObjectId("6560a0ef02a1877734a9df66"), "name": "sensor1", "timestamp": ISODate("2020-01-23T01:00:00.441Z"), "range": 5 }
Aumentar o número de clientes
Aumentar o número de clientes que gravam dados em suas coleções pode melhorar o desempenho.
Otimizar compressão
Para otimizar a compressão de dados para coleções de séries temporais, execute as seguintes ações.
Campos de omissão contendo objetos vazios e arrays de documentos
Para otimizar a compressão, se os dados contiverem objetos ou arrays vazios, omita os campos vazios dos documentos.
Por exemplo, considere os seguintes documentos:
{ "timestamp": ISODate("2020-01-23T00:00:00.441Z"), "coordinates": [1.0, 2.0] }, { "timestamp": ISODate("2020-01-23T00:00:10.441Z"), "coordinates": [] }, { "timestamp": ISODate("2020-01-23T00:00:20.441Z"), "coordinates": [3.0, 5.0] }
A alternância entre campos coordinates
com valores preenchidos e uma array vazia resulta em uma alteração de esquema para o compressor. A mudança de esquema faz com que o segundo e o terceiro documentos da sequência permaneçam descompactados.
Em contraste, os seguintes documentos em que a array vazia é omitida recebem o benefício da compressão ideal:
{ "timestamp": ISODate("2020-01-23T00:00:00.441Z"), "coordinates": [1.0, 2.0] }, { "timestamp": ISODate("2020-01-23T00:00:10.441Z") }, { "timestamp": ISODate("2020-01-23T00:00:20.441Z"), "coordinates": [3.0, 5.0] }
Arredondar dados numéricos para poucos locais decimais
Arredonde os dados numéricos com a precisão necessária para sua aplicação. O arredondamento dos dados numéricos para menos casas decimais melhora a taxa de compactação.
Otimizar o desempenho da consulta
Definir a granularidade apropriada do bucket
Quando você cria uma coleção de séries temporais, o MongoDB agrupa os dados de série temporal recebidos em buckets. Ao definir com precisão a granularidade, você controla a frequência com que os dados são colocados em buckets com base na taxa de ingestão de seus dados.
A partir do MongoDB 6.3, você pode usar os parâmetros de bucketing personalizados bucketMaxSpanSeconds
e bucketRoundingSeconds
para especificar os limites do bucket e controlar com mais precisão como os dados de série temporal são compartimentados.
Você pode melhorar o desempenho definindo os parâmetros de bucketing granularity
ou personalizados para a melhor correspondência referente ao intervalo de tempo entre as medições recebidas da mesma fonte de dados. Por exemplo, ao gravar dados meteorológicos com milhares de sensores, e apenas gravar dados de cada sensor uma vez a cada 5 minutos, você pode definir a granularity
em "minutes"
ou definir os parâmetros de bucketing personalizados para 300
(segundos).
Neste caso, definir a granularity
em hours
junta até um mês de eventos de ingestão de dados em um único bucket, resultando em tempos de travessia mais longos e queries mais lentas. Configurá-la como seconds
resulta em vários buckets por intervalo de sondagem, muitos dos quais podem conter somente um único documento.
A tabela abaixo mostra o intervalo de tempo máximo incluído em um bucket de dados ao utilizar um determinado valor granularity
:
granularity | granularity limite de bucket |
---|---|
seconds | 1 hora |
minutes | 24 horas |
hours | 30 dias |
Criar índices secundários
Para melhorar o desempenho da query, crie um ou mais índices secundários no seu timeField
e metaField
para suportar padrões de query comuns. Nas versões 6.3 e superior, o MongoDB cria automaticamente um índice secundário no timeField
e no metaField
.
Query de metaFields em subcampos
O MongoDB reordena os metaFields de coleções de séries temporais, o que pode fazer com que os servidores armazenem dados em uma ordem de campo diferente dos aplicativos. Se metaFields forem objetos, queries em metaFields inteiros podem produzir resultados inconsistentes, pois a ordem de metaField pode variar entre servidores e aplicativos. Para otimizar queries em metaFields de séries temporais, consulte timeseries metaFields em subcampos escalares em vez de metaFields inteiros.
O exemplo a seguir cria uma coleção de séries temporais:
db.weather.insertMany( [ { "metaField": { "sensorId": 5578, "type": "temperature" }, "timestamp": ISODate( "2021-05-18T00:00:00.000Z" ), "temp": 12 }, { "metaField": { "sensorId": 5578, "type": "temperature" }, "timestamp": ISODate( "2021-05-18T04:00:00.000Z" ), "temp": 11 } ] )
A seguinte query nos subcampos escalares sensorId
e type
retorna o primeiro documento que corresponde aos critérios da query:
db.weather.findOne( { "metaField.sensorId": 5578, "metaField.type": "temperature" } )
Saída de exemplo:
{ _id: ObjectId("6572371964eb5ad43054d572"), metaField: { sensorId: 5578, type: 'temperature' }, timestamp: ISODate( "2021-05-18T00:00:00.000Z" ), temp: 12 }
Use $group em vez de Distinct()
Devido à estrutura de dados única das coleções de séries temporais, o MongoDB não pode indexá-las de forma eficiente para valores diferentes. Evite usar o comando distinct
ou método assistente db.collection.distinct()
em coleções de séries temporais. Em vez disso, use uma agregação $group
para agrupar documentos por valores distintos.
Por exemplo, para consultar valores meta.type
diferentes em documentos onde meta.project = 10
, em vez de:
db.foo.distinct("meta.type", {"meta.project": 10})
Usar:
db.foo.createIndex({"meta.project":1, "meta.type":1}) db.foo.aggregate([{$match: {"meta.project": 10}}, {$group: {_id: "$meta.type"}}])
Isso funciona da seguinte maneira:
Criando um índice composto em
meta.project
emeta.type
e é compatível com a agregação.O estágio
$match
filtra documentos ondemeta.project = 10
.O estágio
$group
usameta.type
como a chave de grupo para gerar um documento por valor exclusivo.