Implementation of Storage Optimization for Android Optimization
- 2021-09-16 08:01:22
- OfStack
Interchange data format
Protocal Buffers introduced by Google is a lighter and more efficient storage structure, but it consumes a lot of memory.
FlatBuffers is also introduced by Google, which focuses on performance and is suitable for mobile terminals. It takes up more storage than Protocal.
SharePreferences Optimization
Bitmap decoding
4.4 The above decodeFile does not use cache internally, which is inefficient. To use decodeStream, the incoming file stream is BufferedInputStream. decodeResource also has performance problems, so use decodeResourceStream.Database optimization
1. Use StringBuilder instead of String
2. Fewer result sets and fewer fields are returned when querying
When querying, only the required fields and result sets are taken. More result sets consume more time and memory, and more fields will lead to more memory consumption.
3. Use less cursor. getColumnIndex
The time consumption of cursor. getColumnIndex is almost the same as that of cursor. getInt, based on observations during performance tuning. You can remember the index of a column with static variable when building a table, and call the corresponding index directly instead of every query.
4. Asynchronous Threads
Table query may not take much time when there is little data in Android, It will not cause ANR, but when it is larger than 100ms, it will also make users feel delay and jamming, which can be put into threads to run. However, sqlite has limitations in concurrency, and multithreading control is troublesome. At this time, you can use a single thread pool to perform db operations in tasks, and return results through handler to interact with UI threads, which will not affect UI threads, but also prevent abnormalities caused by concurrency.
5. SQLiteOpenHelper maintains one singleton
Because SQLite's support for multithreading is not perfect, if two threads operate the database at the same time, because the database is occupied by another thread, an exception of "Database is locked" will be reported in this case. Therefore, using singleton schema in database management class can ensure that no matter which thread gets the database object, it is the same one.
The best way is to manage all database operations from 1 to the same thread queue, while the business layer uses cache synchronization, which can completely avoid the asynchronous and deadlock problems caused by multi-threaded database operation.
6. Initialization in Application
Create a database using Context of Application and close it at the end of the Application life cycle. Initialize the database first in the process of application startup, so as to avoid the long operation time caused by initialization after entering the application.7. Use less AUTOINCREMENT
After adding AUTOINCREMENT to the primary key, it can be guaranteed that the primary key is strictly incremented, but it cannot be guaranteed to add 1 every time, because after the insertion fails, the failed line number will not be multiplexed, which will cause the primary key to be spaced, and then INSERT will take more than one time.
This AUTOINCREMENT keyword increases the burden on CPU, memory, disk space, and disk I/O, so try not to use it unless necessary. It is usually not necessary.
Affairs
The two major benefits of using transactions are atomic commit and better performance:
Atomic Commit: Means that all modifications within the same transaction are either completed or not made. If a modification fails, it will be automatically rolled back so that all modifications will not take effect. Better performance: Sqlite creates 1 transaction for each insert and update operation by default and commits immediately after each insert and update. So if you insert data 100 times in a row, you're actually creating a transaction, executing a statement, and committing the process is repeated 100 times. If you explicitly create a transaction, this process is only done once, and the performance can be greatly improved by this one-time transaction. Especially when the database is located on the sd card, the time can be saved by about two orders of magnitude.There are three main methods: beginTransaction, setTransactionSuccessful and endTransaction.
SQLiteStatement
Using Android system provides SQLiteStatement to insert data, the performance has a definite improvement, and also solves the problem of SQL injection.
SQLiteStatement statement = dbOpenHelper.getWritableDatabase().compileStatement("INSERT INTO EMPERORS(name, dynasty, start_year) values(?,?,?)");
statement.clearBindings();
statement.bindString(1, "Max");
statement.bindString(2, "Luk");
statement.bindString(3, "1998");
statement.executeInsert();
SQLiteStatement can only insert data from 1 table, and the last data should be cleared before inserting.
Index
Indexes are like catalogues of books, which can quickly find the number of pages. Indexes in databases can help find data quickly without scanning the whole table. Appropriate indexes can greatly improve the efficiency of database query.
Advantages: It greatly accelerates the speed of database retrieval, including single table query, linked table query, grouping query and sorting query. It is often one to two orders of magnitude of performance improvement, and it grows with the order of magnitude of data.
Disadvantages:
Indexes are expensive to create and maintain. Indexes take up physical space and increase with the amount of data. Indexes need to be maintained when adding, deleting and modifying the database, so the performance of adding, deleting and modifying will be affected.
Classification
1. Create indexes directly and indirectly
Direct creation: Use sql statement to create, Android can be created in onCreate of SQLiteOpenHelper or onUpgrade directly excuSql statement, such asCREATE INDEX mycolumn_index ON mytable (myclumn)
Indirect creation: Defines a primary key constraint or a uniqueness key constraint. Indexes can be created indirectly. The primary key defaults to a uniqueness index.
2. General index and uniqueness index
General index:CREATEINDEXmycolumn_indexONmytable(myclumn)
Uniqueness index: Ensure that all data in the index column is uniqueness. It can be used for both clustered and non-clustered indexes. The statement is
CREATE UNIQUE COUSTERED INDEX myclumn_cindex ON mytable(mycolumn)
3. Single index and composite index
Single index: An index building statement contains only a single field, as in the normal index and uniqueness index creation examples above. Composite index: Also called composite index, which contains multiple fields in the index building statement at the same time, such asCREATEINDEXname_indexONusername(firstname,lastname),
Where firstname is the leading column.
4. Clustered index and non-clustered index (clustered index, clustered index)
Clustered index: Physical index, which is the same as the physical order of the base table, and the order of data values is always arranged in order, such as CREATE CLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn) WITH ALLOW_DUP_ROW
, of which
WITH ALLOW_DUP_ROW
Represents a clustered index that allows duplicate records
Non-clustered index:
CREATEUNCLUSTEREDINDEXmycolumn_cindexONmytable(mycolumn),
The index defaults to a non-clustered index
Usage scenario
(>, <, =,>=, <=)
Or
order by
,
group by
Indexes are recommended when occurring. And the greater the selectivity (the number of only one value in a field/the total number), the more advantageous it is to build an index
Multiple columns are often accessed at the same time, and each column contains duplicate values, so you can consider building a composite index
Usage rules
CREATEINDEXmycolumn_indexONmytable(myclumn)
0
,
select * from student where class = 2
The index is not used,
select * from dept where grade = 3
Indexes are used
Avoid evaluating index columns. Any evaluation of where clause columns that cannot be compiled and optimized will invalidate the index when querying
select * from student where tochar(grade)='2
Avoid using NULL for comparison values
When querying multiple tables, we should pay attention to selecting the appropriate table as the inner table. Join conditions should fully consider the table with index and the table with more rows. The selection of inner and outer surfaces can be determined by the formula: the number of matching rows in the outer table * the number of times of searching every time in the inner table, and the minimum product is the best scheme. Before the actual multi-table operation is actually executed, the query optimizer lists several possible join schemes according to the join conditions and finds the best scheme with the least system overhead
Query column and index column order 1
Replace EXISTS clause with multi-table join
Put the condition with the largest number of filtered records first
Good at using stored procedures, which makes sql more flexible and efficient (Sqlite does not support stored procedures)
Other general optimizations
Frequently used data is cached after reading, so as to avoid "write amplification" caused by repeated reading and writing. Sub-threads read and write data When ObjectOutputStream serializes the disk, it saves each object in memory to the disk. When saving the object, each data member will bring one I/O operation. Encapsulate an output stream ByteArrayOutputStream or BufferedOutputStream above ObjectOutputStream, first write the serialized information to the buffer area, and then write it to the disk once again; Accordingly, replace ObjectInputStream with ByteArrayInputStream or BufferedInputStream. Choose the size of buffer Buffer reasonably. Too small leads to more I/O operations, and too large leads to longer application time. For example, 4-8 KB.