Enhance Performance on Large Datasets

Remote Operations

We recommend server-side data processing for large datasets. The ODataStore supports server-side paging, filtering, and sorting. DevExtreme provides extensions that help implement data processing for ASP.NET and PHP servers. You can also use the third-party extension for MongoDB. If these extensions do not suit your data source, implement server-side data processing manually according to the protocol described in the Custom Sources article.

Specify the remoteOperations option to notify the DataGrid of the server's data processing operations.

jQuery
JavaScript
$(function() {
    $("#dataGridContainer").dxDataGrid({ 
        // ...
        remoteOperations: {
            filtering: true,
            paging: true,
            sorting: true,
            groupPaging: true,
            grouping: true,
            summary: true
        }
    });
}); 
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-remote-operations
        [filtering]="true"
        [paging]="true"
        [sorting]="true"
        [summary]="true"
        [grouping]="true"
        [groupPaging]="true"> 
    </dxo-remote-operations>
</dx-data-grid>
import { DxDataGridModule } from 'devextreme-angular';
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

Deferred Selection

Use the deferred mode to increase the DataGrid's performance when selecting multiple rows at once. In this mode, only the API - for example, the getSelectedRowsData() or getSelectedRowKeys() method - can request the DataGrid data. Assign true to the selection.deferred option to use deferred selection.

jQuery
JavaScript
$(function(){
    $("#dataGridContainer").dxDataGrid({
        // ...
        dataSource: {
            store: {
                type: "odata",
                url: "https://js.devexpress.com/Demos/DevAV/odata/Products",
                key: "Product_ID"
            }
        },
        selection: {
            mode: 'multiple',
            allowSelectAll: true,
            deferred: true
        }
    }); 
});
Angular
HTML
TypeScript
<dx-data-grid
    [dataSource]="dataSource">
    <dxo-selection
        mode="multiple"
        [allowSelectAll]="true"
        [deferred]="true">
    </dxo-selection>
</dx-data-grid>
import { DxDataGridModule } from 'devextreme-angular';
import 'devextreme/data/odata/store';
// ...
export class AppComponent {
    dataSource = {
        store: {
            type: "odata",
            url: "https://js.devexpress.com/Demos/DevAV/odata/Products",
            key: "Product_ID"
        }
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
NOTE
You must specify the key option of the Store underlying the dataSource to guarantee that the deferred selection works properly.

The following tasks require using different API in the deferred mode comparing with usual (instant) one:

  • Setting initial selection

    The deferred mode requires using the selectionFilter instead of the selectedRowKeys option to set the initially selected rows. Pass a filter expression to define records that must be selected.

    jQuery
    JavaScript
    $(function () {
        $("#dataGridContainer").dxDataGrid({
            // ...
            selectionFilter: ["Task_Status", "=", "Completed"]
        });
    });
    Angular
    HTML
    TypeScript
    <dx-data-grid ...
        selectionFilter="['Task_Status', '=', 'Completed']">
    </dx-data-grid>
    import { DxDataGridModule } from 'devextreme-angular';
    // ...
    export class AppComponent {
        // ...
    }
    @NgModule({
        imports: [
            // ...
            DxDataGridModule
        ],
        // ...
    })

    The DataGrid changes the selectionFilter option's value internally each time a user selects a row. You can use the following code to obtain this option's current value and send it to the server:

    jQuery
    JavaScript
    function sendSelectedRows() {
        var selectionFilter = dataGridInstance.option("selectionFilter");
        $.ajax({
            method: "POST",
            url: "url/to/data/processing/method",
            data: { 
                filter: (selectionFilter ? JSON.stringify(selectionFilter) : null)
            }
        });
    }
    Angular
    TypeScript
    import { ..., ViewChild } from '@angular/core';
    import { HttpClient, HttpClientModule } from '@angular/common/http';
    import { DxDataGridModule, DxDataGridComponent } from 'devextreme-angular';
    // ...
    export class AppComponent {
        @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
        constructor(private httpClient: HttpClient) { }
        sendSelectedRows() {
            var selectionFilter = this.dataGrid.instance.option("selectionFilter");
            this.httpClient
                .post('url/to/data/processing/method',  
                "filter: " + (selectionFilter ? JSON.stringify(selectionFilter) : null)
                )
                .subscribe();
        }
    }
    @NgModule({
        imports: [
            // ...
            DxDataGridModule,
            HttpClientModule
        ],
        // ...
    })
  • Checking whether a row is selected

    Use the isRowSelected(data) method to find out whether a specific row is selected.

  • Getting the selected rows' data

    In the deferred mode, the getSelectedRowsData() and getSelectedRowKeys() methods return a native Promise or a jQuery.Promise when you use jQuery. Get the selected data within the callback function that resolves this object.

View Demo

See Also

Lookup Optimization

As a rule, a lookup column contains IDs from a main data source field but displays human-readable values from its own data source. When the DataGrid first launches, it loads data from both data sources which causes performance to decrease.

You can send the human-readable values from the server as a part of the main data source alongside the IDs (like in this example) to optimize the lookup column. In this case, use the column's calculateDisplayValue option to specify which field provides the human-readable values. With this optimization, the lookup data source is not loaded until a user starts editing the lookup column.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        //...
        columns: [{
            caption: "Customer",
            // "CustomerName" provides human-readable values
            calculateDisplayValue: "CustomerName",
            dataField: "CustomerID",
            lookup: {
                valueExpr: "CustomerID",
                displayExpr: "ContactName",
                dataSource: {
                    store: {
                        // ...
                        key: "CustomerID"
                    }
                }
            }
        },
        // ...
        ]
    });
});
Angular
HTML
TypeScript
<dx-data-grid ...>
    <dxi-column
        caption="Customer"
        dataField="CustomerID"
        calculateDisplayValue="CustomerName">   <!-- "CustomerName" provides human-readable values -->
        <dxo-lookup
            [dataSource]="dataSource"
            displayExpr="ContactName"
            valueExpr="CustomerID">
        </dxo-lookup>
    </dxi-column>
</dx-data-grid>
import { DxDataGridModule } from 'devextreme-angular';
import 'devextreme/data/array_store';
// or
// import 'devextreme/data/odata/store';
// import 'devextreme/data/custom_store';
export class AppComponent {
    dataSource: any;
    constructor() {
        this.dataSource = {
            store: {
                // ...
                key: "CustomerID"
            }
        }
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
See Also