Optimizing XamDataGrid Performance Using External Data Operations
Vários aplicativos de linha de negócios usam o XamDataGrid por seu rico conjunto de recursos, alta personalização e desempenho.
Se houve um desenvolvimento constante no uso do XamDataGrid em todos os setores, foi a quantidade crescente de dados exibidos no XamDataGrid. Tradicionalmente, os controles de grade executam operações de dados, como classificação, filtragem e agrupamento por si mesmos no thread da interface do usuário. No entanto, com o aumento das cargas de dados, os desenvolvedores estão procurando maneiras de executar essas operações em um thread separado ou em uma máquina completamente diferente. É por isso que os desenvolvedores nos pediram para que o XamDataGrid passasse os argumentos dessas operações e, sem executar essa operação, exibisse o resultado processado. Adicionamos essa funcionalidade na versão 12.1 e ela nos permitiu melhorar significativamente o desempenho quando grandes conjuntos de dados são associados ao XamDataGrid. Esta postagem no blog descreve como aproveitar essa funcionalidade e descreve suas implicações para o desempenho em termos de volume de memória e tempo necessário para executar uma operação.
Baixe o projeto de exemplo– ele ilustra como ativar o processamento fora da rede de manipulações de dados e compara o desempenho de um XamDataGrid associado ao mesmo conjunto de dados nos dois casos – quando operações internas e externas são usadas. O projeto é criado usando o Visual Studio 2010 e o .NET Framework 4. Ele usa uma versão de avaliação do produto WPF 12.1, para que você possa compilá-lo e executá-lo sem nenhum download adicional. A avaliação gratuita de 30 dias totalmente funcional do produto NetAdvantage para WPF, que inclui o XamDataGrid, está disponível. Aqui está uma captura de tela do projeto de exemplo:

O que há no exemplo
No aplicativo de exemplo, há dois XamDataGrids lado a lado – o da esquerda usa operações internas e o da direita executa essas operações por meio do objeto CollectionView. Ambas as grades estão vinculadas a um conjunto de dados contendo 100.000 registros. Para ilustrar a diferença de desempenho devido a operações internas ou externas, compararemos o desempenho de classificação e agrupamento. No entanto, exatamente os mesmos resultados também se aplicariam à filtragem e aos cálculos resumidos.
Implicações de desempenho do uso de classificação/grupo interno
Por padrão, o XamDataGrid cria apenas objetos de registro para representar os itens de dados que estão visíveis no momento (em oposição a todos os registros no conjunto de dados). No entanto, quando as operações de classificação/grupo são executadas pelo XamDataGrid internamente, ele precisa criar objetos de registro para representar todos os itens no conjunto de dados, para que possa classificá-los/agrupá-los. Embora os elementos da interface do usuário não sejam criados para todos esses registros devido à lógica de virtualização da interface do usuário do XamDataGrid, os objetos de registro podem ter um impacto substancial no volume de memória do aplicativo (como veremos na comparação de desempenho abaixo), especialmente quando os conjuntos de dados associados ao XamDataGrid são grandes. Então, como isso afeta o desempenho? Na primeira vez que um usuário classifica/agrupa uma grade, há um atraso durante o qual o XamDataGrid cria objetos de registro para todos os itens de dados e, em seguida, executa a operação solicitada pelo usuário. Isso coloca todo o conjunto de dados na memória em termos de objetos de registro gerenciados pelo XamDataGrid. Embora isso aumente o volume de memória e cause um atraso na primeira vez que essa operação é executada, as operações subsequentes de classificação/grupo são bastante rápidas, porque todo o conjunto de dados já está na memória.
Vamos ver como isso afeta o desempenho. Execute o exemplo e classifique ou agrupe o XamDataGridà esquerda – você verá a alteração de volume de tempo e memória (delta) relatada acima dele. Na minha máquina, quando a grade de operações internas é classificada pela primeira vez, a operação leva 4,3 segundos e o consumo de memória aumenta em 40 MB. As classificações subsequentes levam cerca de 1 segundo e o volume de memória permanece o mesmo (já que já está no máximo – todos os itens de dados são representados como objetos de registro). Depois que o conjunto de dados já estiver totalmente carregado, o agrupamento levará cerca de 2,8 segundos, desagrupando 1,2 segundos.
Implicações de desempenho do uso de classificação/grupo externo
Você pode controlar como os cálculos de classificação, agrupamento, filtragem e resumo são executados usando as propriedades SortEvaluationMode,GroupByEvaluationMode,FilterEvaluationMode e SummaryEvaluationMode. Eles permitem desabilitar a classificação, o agrupamento, a filtragem e os cálculos de resumo internos e executá-los manualmente ou por meio do objeto CollectionView. Isso significa que a grade não precisa inicializar objetos de registro para representar todo o conjunto de dados – em vez disso, ela depende do back-end para reordenar o conjunto de dados. No caso de usar o modo de exibição de coleção (definindo as propriedades acima como "UseCollectionView"), isso não requer nenhuma implementação de lógica extra. No entanto, se você tiver um servidor de back-end, onde os cálculos/reordenações são executados, poderá usar a configuração Manual para as propriedades acima. Isso fará com que o XamDataGrid dispare os eventos Sorting / Grouping / RecordFilterChanging, permitindo que você os passe para o back-end, onde os cálculos são executados. O XamDataGrid exibirá o conjunto de dados reordenado depois que ele for processado pelo back-end.
O uso das configurações UseCollectionView e Manual para a classificação/agrupamento salva o XamDataGrid da necessidade de instanciar objetos de registro para todo o conjunto de dados, mantendo assim o volume de memória constantemente baixo. O componente de tempo do desempenho depende do back-end que você está usando para o processamento dessas operações. Neste exemplo, no XamDataGridà direita, estamos usando o objeto CollectionView para lidar com essas operações em vez da lógica interna.
Que tal desempenho neste caso? Execute o exemplo e classifique ou agrupe o XamDataGridà direita – a alteração de tempo e volume de memória será relatada logo acima. Quando a classificação e o agrupamento são executados pelo collectionView (usando o valor UseCollectionView para as propriedades SortEvaluationMode e GroupByEvaluationMode), o volume de memória permanece o mesmo e o tempo necessário é o seguinte – classificação de 2,5 segundos, agrupamento de 4,9 segundos, desagrupamento de 2,5 segundos. Há três pontos a serem mencionados aqui:
1. O volume de memória permanece constante, porque nenhum objeto de registro extra é instanciado devido à classificação/agrupamento
2. O tempo que leva para classificar/agrupar é constante, ou seja, não há atraso significativo ao realizar a primeira classificação/grupo (como é o caso quando operações internas são usadas, devido à inicialização de objetos de registro)
3. O tempo que leva para classificar/agrupar é maior do que o tempo necessário para executar as mesmas operações se forem usadas operações internas. No entanto, o aspecto de tempo do desempenho depende inteiramente do back-end que você gostaria de usar para essas operações. Mesmo assim, o uso dos objetos collectionView oferece baixo consumo de memória e bom desempenho de classificação/grupo na primeira vez (enquanto no caso de operações internas você tem um atraso extra na primeira vez que uma operação é executada) e pode ser útil em alguns casos.
Summary Calculations
Os cálculos de resumo internos padrão exigem que a grade inicialize objetos de registro para representar todo o conjunto de dados. Usando a propriedade SummaryEvaluationMode, os cálculos de resumo também podem ser executados usando o Linq ou manualmente. Embora o uso do Linq não exija nenhuma implementação extra de sua parte, o uso do modo de computação manual requer a manipulação do evento QuerySummaryResult, onde você pode executar sua própria lógica de avaliação e fornecer um valor para o resultado do resumo. O uso do modo manual permite manter o consumo de memória baixo e oferece a oportunidade de melhorar o tempo de cálculo o máximo possível, otimizando o back-end.
Resumo
Nesta postagem do blog, apresentei como definir o XamDataGrid para executar cálculos de classificação/agrupamento/filtragem/resumo externamente. Descrevemos a API a ser usada para essa finalidade e analisamos as implicações de desempenho do uso de operações externas. O projeto de exemplo pode ser usado para demonstrar facilmente a diferença entre os dois cenários e pode ser facilmente alterado para permitir que você veja a melhoria no desempenho que você veria ao associar seus próprios dados a ele. Usando o modo manual, você pode essencialmente remover quaisquer limitações de classificação/agrupamento/filtragem/resumos impostas até agora pelo hardware da máquina cliente que executa seu aplicativo – usar uma poderosa máquina de back-end de cálculo é a melhor maneira de processar grandes conjuntos de dados com eficiência, ao mesmo tempo em que fornece uma interface de usuário rápida e responsiva. Você pode começar conversando com os usuários de seus aplicativos e descobrindo as exibições em que eles se beneficiariam de maiores quantidades de dados sendo exibidas para ajudá-los a tomar uma decisão. Depois de descobrir sobre eles, o XamDataGrid ajudará você a atender à crescente fome de seus usuários por mais dados a serem exibidos, ao mesmo tempo em que oferece uma excelente experiência ao usuário.