Secondary indexes improve query efficiency in various scenarios. You can create an index on specified columns. The data in the resulting index table is sorted by these index columns. When you write data to the primary table, the data is automatically synchronized to the index table, which you can then query to retrieve data quickly.
Example scenario
In a phone call record query scenario, information about each call is stored in a data table after the call ends.
The primary key and predefined columns of the data table are as follows:
-
CellNumber and StartTime are the primary keys. They represent the calling number and the call start time, respectively.
-
CalledNumber, Duration, and BaseStationNumber are predefined columns. They represent the called number, call duration, and base station number, respectively.
The following table shows sample data from the data table. The wide table model of Tablestore sorts all rows by primary key and provides the sequential scan (GetRange) operation to read data.
|
CellNumber |
StartTime (UNIX timestamp) |
CalledNumber |
Duration |
BaseStationNumber |
|
123456 |
1532574644 |
654321 |
60 |
1 |
|
234567 |
1532574714 |
765432 |
10 |
1 |
|
234567 |
1532574734 |
123456 |
20 |
3 |
|
345678 |
1532574795 |
123456 |
5 |
2 |
|
345678 |
1532574861 |
123456 |
100 |
2 |
|
456789 |
1532584054 |
345678 |
200 |
3 |
Consider the following query requirements. You can retrieve the required data from the primary table, a global secondary index, or a local secondary index as needed.
-
Query all outgoing call records for the number 234567.
-
Query all incoming call records for the number 123456.
-
Query all call records from base station 002 that started at or after timestamp 1532574740.
-
Query the duration of all calls that occurred at base station 003 between timestamps 1532574861 and 1532584054.
-
Query the total, average, maximum, and minimum duration of all calls that occurred at base station 003 between timestamps 1532574861 and 1532584054.
-
Query all call records from the calling number 456789 to the called number 345678.
Data query
Select the appropriate query method for each requirement.
Implementation methods
The following table describes the implementation method for each query requirement.
-
For an example of how to create a table and a secondary index, see Appendix: Example of creating a data table and secondary indexes.
After you create the primary table, write the sample data to it. The data is automatically synchronized to the index table. For more information about how to write data, see Write data.
-
The system automatically performs primary key completion. This means that the primary key columns of the primary table are added to the index columns to form the primary key of the index table.
-
The first primary key column of a local secondary index must be the same as the first primary key column of the primary table.
|
Query requirement |
Implementation method |
|
Query all outgoing call records for the number 234567. |
You can call the getRange interface to scan the data table. |
|
Query all incoming call records for the number 123456. |
Create an index on the CalledNumber column. Then, call the getRange operation to scan the index table. |
|
Query all call records from base station 002 that started at or after timestamp 1532574740. |
Create a compound index on the BaseStationNumber and StartTime columns. Then, call the getRange operation to scan the index table (a global secondary index). |
|
Query the duration of all calls that occurred at base station 003 between timestamps 1532574861 and 1532584054. |
Create a compound index on the BaseStationNumber and StartTime columns and return only the Duration column. Then, call the getRange operation to scan the index table (a global secondary index). You can manually look up the primary table to retrieve the value of the Duration column or include the Duration column as an attribute column in the index table. To query the total, average, maximum, and minimum duration of all calls that occurred at base station 003 between timestamps 1532574861 and 1532584054, you can use the same implementation method. Then, you can calculate the final results from the returned duration of each call. Note
You can also use Tablestore SQL queries. This way, you do not need to perform calculations on the client. You can use an SQL statement to directly retrieve the final statistical results. For more information, see Query data. |
|
Query all call records from the calling number 456789 to the called number 345678. |
Create a compound index on the CellNumber and CalledNumber columns. Include the Duration and BaseStationNumber columns as attribute columns in the index table. Then, call the getRange operation to scan the index table (a local secondary index). |
Query all outgoing call records for the number 234567
Query all incoming call records for the number 123456
Query all call records from base station 002 that started at or after timestamp 1532574740
Query the duration of all calls that occurred at base station 003 between timestamps 1532574861 and 1532584054
Query all call records from the calling number 456789 to the called number 345678
Appendix: Example of creating a data table and secondary indexes
The following example shows how to create the primary table and secondary indexes, including local and global secondary indexes, that are used in this topic.
private static final String TABLE_NAME = "CallRecordTable";
private static final String INDEX0_NAME = "IndexOnBeCalledNumber";
private static final String INDEX1_NAME = "IndexOnBaseStation1";
private static final String INDEX2_NAME = "IndexOnBaseStation2";
private static final String INDEX3_NAME = "LocalIndexOnBeCalledNumber";
private static final String PRIMARY_KEY_NAME_1 = "CellNumber";
private static final String PRIMARY_KEY_NAME_2 = "StartTime";
private static final String DEFINED_COL_NAME_1 = "CalledNumber";
private static final String DEFINED_COL_NAME_2 = "Duration";
private static final String DEFINED_COL_NAME_3 = "BaseStationNumber";
private static void createTable(SyncClient client) {
TableMeta tableMeta = new TableMeta(TABLE_NAME);
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema(PRIMARY_KEY_NAME_1, PrimaryKeyType.INTEGER));
tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema(PRIMARY_KEY_NAME_2, PrimaryKeyType.INTEGER));
tableMeta.addDefinedColumn(new DefinedColumnSchema(DEFINED_COL_NAME_1, DefinedColumnType.INTEGER));
tableMeta.addDefinedColumn(new DefinedColumnSchema(DEFINED_COL_NAME_2, DefinedColumnType.INTEGER));
tableMeta.addDefinedColumn(new DefinedColumnSchema(DEFINED_COL_NAME_3, DefinedColumnType.INTEGER));
// The time-to-live (TTL) of the data, in seconds. A value of -1 means that the data never expires. The TTL for a primary table with an index table must be -1.
int timeToLive = -1;
// The maximum number of versions to save. The max versions for a primary table with an index table must be 1.
int maxVersions = 1;
TableOptions tableOptions = new TableOptions(timeToLive, maxVersions);
ArrayList<IndexMeta> indexMetas = new ArrayList<IndexMeta>();
IndexMeta indexMeta0 = new IndexMeta(INDEX0_NAME);
indexMeta0.addPrimaryKeyColumn(DEFINED_COL_NAME_1);
indexMetas.add(indexMeta0);
IndexMeta indexMeta1 = new IndexMeta(INDEX1_NAME);
indexMeta1.addPrimaryKeyColumn(DEFINED_COL_NAME_3);
indexMeta1.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2);
indexMetas.add(indexMeta1);
IndexMeta indexMeta2 = new IndexMeta(INDEX2_NAME);
indexMeta2.addPrimaryKeyColumn(DEFINED_COL_NAME_3);
indexMeta2.addPrimaryKeyColumn(PRIMARY_KEY_NAME_2);
indexMeta2.addDefinedColumn(DEFINED_COL_NAME_2);
indexMetas.add(indexMeta2);
IndexMeta indexMeta3 = new IndexMeta(INDEX3_NAME);
indexMeta3.addPrimaryKeyColumn(PRIMARY_KEY_NAME_1);
indexMeta3.addPrimaryKeyColumn(DEFINED_COL_NAME_1);
indexMeta3.addDefinedColumn(DEFINED_COL_NAME_2);
indexMeta3.addDefinedColumn(DEFINED_COL_NAME_3);
// Set the index synchronization mode.
indexMeta3.setIndexUpdateMode(IUM_SYNC_INDEX);
// Set the index type to IT_LOCAL_INDEX (local secondary index).
indexMeta3.setIndexType(IT_LOCAL_INDEX);
indexMetas.add(indexMeta3);
CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions, indexMetas);
client.createTable(request);
}