Android cung cấp tính năng hỗ trợ tích hợp cho SQLite, một cơ sở dữ liệu SQL hiệu quả. Hãy làm theo các phương pháp hay nhất này để tối ưu hoá hiệu suất của ứng dụng, đảm bảo rằng khi dữ liệu của bạn phát triển thì ứng dụng vẫn chạy nhanh và dễ dự đoán. Bằng cách áp dụng các phương pháp hay nhất này, khả năng bạn gặp phải các vấn đề về hiệu suất và khắc phục sự cố sẽ giảm nhiều.
Để đạt được hiệu suất nhanh hơn, hãy làm theo các nguyên tắc về hiệu suất sau:
Đọc ít hàng và cột hơn: Tối ưu hoá các truy vấn của bạn để chỉ truy xuất dữ liệu cần thiết. Giảm lượng dữ liệu được đọc từ cơ sở dữ liệu, vì việc truy xuất dữ liệu quá mức có thể ảnh hưởng đến hiệu suất.
Đưa công việc lên công cụ SQLite: Thực hiện các phép tính, lọc và sắp xếp trong truy vấn SQL. Việc sử dụng công cụ truy vấn của SQLite có thể cải thiện đáng kể hiệu suất.
Sửa đổi giản đồ cơ sở dữ liệu: Hãy thiết kế giản đồ cơ sở dữ liệu để giúp SQLite xây dựng các kế hoạch truy vấn và thể hiện dữ liệu hiệu quả. Hãy lập chỉ mục bảng đúng cách và tối ưu hoá cấu trúc bảng để nâng cao hiệu suất.
Ngoài ra, bạn có thể sử dụng các công cụ khắc phục sự cố hiện có để đo lường hiệu suất của cơ sở dữ liệu SQLite nhằm xác định những khía cạnh cần tối ưu hoá.
Bạn nên dùng thư viện Jetpack Room.
Định cấu hình cơ sở dữ liệu nhằm đạt được hiệu suất
Hãy làm theo các bước trong phần này để định cấu hình cơ sở dữ liệu nhằm đạt được hiệu suất tối ưu trong SQLite.
Bật tính năng Ghi nhật ký trước
SQLite triển khai các phép biến đổi bằng cách thêm chúng vào nhật ký mà đôi khi sẽ nén vào cơ sở dữ liệu. Tính năng này được gọi là Ghi nhật ký trước (Write-Ahead Logging – WAL).
Hãy bật tính năng WAL, trừ phi bạn sử dụng ATTACH
DATABASE
.
Nới lỏng chế độ đồng bộ hoá
Theo mặc định, khi sử dụng WAL, mọi lệnh xác nhận đều đưa ra một fsync
để đảm bảo rằng dữ liệu đến được ổ đĩa. Điều này giúp dữ liệu khó bị hỏng hơn, nhưng làm chậm lệnh xác nhận.
SQLite cho phép bạn lựa chọn kiểm soát chế độ đồng bộ. Nếu bạn bật WAL, hãy thiết lập chế độ đồng bộ thành NORMAL
:
Kotlin
db.execSQL("PRAGMA synchronous = NORMAL")
Java
db.execSQL("PRAGMA synchronous = NORMAL");
Trong chế độ cài đặt này, một lệnh xác nhận có thể trả về trước khi dữ liệu được lưu trữ trong ổ đĩa. Trong trường hợp thiết bị bị tắt, chẳng hạn như mất điện hoặc hoảng loạn hạt nhân, thì dữ liệu đã xác nhận có thể bị mất. Tuy nhiên, nhờ việc ghi nhật ký, cơ sở dữ liệu của bạn sẽ không bị hỏng.
Nếu chỉ có ứng dụng của bạn gặp sự cố, dữ liệu của bạn vẫn sẽ đến được ổ đĩa. Đối với hầu hết ứng dụng, chế độ cài đặt này giúp cải thiện hiệu suất mà không hao tổn tài nguyên.
Xác định giản đồ bảng hiệu quả
Để tối ưu hoá hiệu suất và giảm thiểu mức sử dụng dữ liệu, hãy xác định một giản đồ bảng hiệu quả. SQLite xây dựng các kế hoạch và dữ liệu để truy vấn hiệu quả, giúp truy xuất dữ liệu nhanh hơn. Phần này cung cấp các phương pháp hay nhất để tạo giản đồ bảng.
Cân nhắc sử dụng INTEGER PRIMARY KEY
Đối với ví dụ này, hãy xác định và điền vào bảng như sau:
CREATE TABLE Customers(
id INTEGER,
name TEXT,
city TEXT
);
INSERT INTO Customers Values(456, 'John Lennon', 'Liverpool, England');
INSERT INTO Customers Values(123, 'Michael Jackson', 'Gary, IN');
INSERT INTO Customers Values(789, 'Dolly Parton', 'Sevier County, TN');
Kết quả của bảng như sau:
rowid | id | tên | thành phố |
---|---|---|---|
1 | 456 | John Lennon | Liverpool, Anh |
2 | 123 | Michael Jackson | Gary, Indiana |
3 | 789 | Dolly Parton | Quận Sevier, TN |
Cột rowid
là một chỉ mục lưu giữ thứ tự chèn. Các truy vấn lọc theo rowid
sẽ được triển khai dưới dạng tìm kiếm cây B nhanh, nhưng các truy vấn lọc theo id
sẽ được triển khai dưới dạng quét bảng chậm.
Nếu dự định thực hiện tra cứu theo id
, bạn có thể tránh lưu trữ cột rowid
để có ít dữ liệu hơn trong bộ nhớ và nhanh hơn về cơ sở dữ liệu tổng thể:
CREATE TABLE Customers(
id INTEGER PRIMARY KEY,
name TEXT,
city TEXT
);
Bây giờ, bảng của bạn sẽ có dạng như sau:
id | tên | thành phố |
---|---|---|
123 | Michael Jackson | Gary, Indiana |
456 | John Lennon | Liverpool, Anh |
789 | Dolly Parton | Quận Sevier, TN |
Vì bạn không cần lưu trữ cột rowid
nên truy vấn id
sẽ có tốc độ nhanh. Lưu ý rằng bảng hiện được sắp xếp dựa trên id
thay vì thứ tự chèn.
Tăng tốc truy vấn bằng chỉ mục
Sử dụng SQLite
chỉ mục
để tăng tốc độ truy vấn. Khi lọc (WHERE
), sắp xếp (ORDER BY
) hoặc tổng hợp (GROUP BY
) một cột, nếu bảng có chỉ mục cho cột, thì truy vấn sẽ được tăng tốc.
Trong ví dụ trước, việc lọc theo city
yêu cầu phải quét toàn bộ bảng:
SELECT id, name
WHERE city = 'London, England';
Đối với ứng dụng có nhiều truy vấn theo "thành phố", bạn có thể tăng tốc các truy vấn đó bằng một chỉ mục:
CREATE INDEX city_index ON Customers(city);
Chỉ mục sẽ được triển khai dưới dạng bảng bổ sung, được sắp xếp theo cột chỉ mục và được ánh xạ tới rowid
:
thành phố | rowid |
---|---|
Gary, Indiana | 2 |
Liverpool, Anh | 1 |
Quận Sevier, TN | 3 |
Xin lưu ý rằng dung lượng lưu trữ của cột city
hiện hao tổn gấp đôi vì có trong cả bảng ban đầu và chỉ mục. Vì bạn đang sử dụng chỉ mục, mức hao tổn thêm dung lượng lưu trữ sẽ đánh đổi bằng việc truy vấn nhanh hơn.
Tuy nhiên, không nên duy trì chỉ mục mà bạn không dùng để tránh phải hao tổn dung lượng lưu trữ mà không đạt được hiệu suất truy vấn.
Tạo chỉ mục nhiều cột
Nếu truy vấn của bạn kết hợp nhiều cột, bạn có thể tạo nhiều cột chỉ mục để đẩy nhanh tốc độ hoàn toàn của truy vấn. Bạn cũng có thể sử dụng chỉ mục trên cột bên ngoài và cho phép cột bên trong thực hiện tìm kiếm dưới dạng quét lần lượt từng mục.
Ví dụ: với truy vấn sau:
SELECT id, name
WHERE city = 'London, England'
ORDER BY city, name
Bạn có thể tăng tốc truy vấn bằng chỉ mục nhiều cột theo thứ tự được chỉ định trong truy vấn:
CREATE INDEX city_name_index ON Customers(city, name);
Tuy nhiên, nếu bạn chỉ có một chỉ mục trên city
, thì thứ tự bên ngoài vẫn được tăng tốc, trong khi thứ tự bên trong cần phải được quét lần lượt từng mục.
Điều này cũng áp dụng với các truy vấn có tiền tố. Ví dụ: chỉ mục ON Customers (city, name)
cũng tăng tốc độ lọc, sắp xếp và nhóm theo city
, vì bảng chỉ mục cho chỉ mục nhiều cột được sắp xếp theo thứ tự nhất định của các chỉ số có sẵn.
Cân nhắc sử dụng WITHOUT ROWID
Theo mặc định, SQLite sẽ tạo một cột rowid
cho bảng của bạn, trong đó rowid
là INTEGER PRIMARY KEY AUTOINCREMENT
ngầm ẩn. Nếu bạn đã có một cột là INTEGER PRIMARY KEY
, thì cột này sẽ trở thành bí danh của rowid
.
Đối với các bảng có khoá chính khác INTEGER
hoặc một tổ hợp gồm nhiều cột, hãy cân nhắc sử dụng WITHOUT
ROWID
.
Lưu trữ dữ liệu nhỏ dưới dạng BLOB
và lưu trữ dữ liệu lớn dưới dạng tệp
Nếu muốn liên kết dữ liệu lớn (ví dụ: hình thu nhỏ của một hình ảnh hoặc ảnh của một người liên hệ) với một hàng, bạn có thể lưu trữ dữ liệu đó trong cột BLOB
hoặc trong một tệp và sau đó lưu trữ đường dẫn tệp trong cột.
Các tệp thường được làm tròn lên đến 4 KB. Đối với các tệp rất nhỏ có lỗi làm tròn đáng kể, sẽ hiệu quả hơn nếu bạn lưu trữ các tệp này trong cơ sở dữ liệu dưới dạng BLOB
. SQLite sẽ giảm thiểu các lệnh gọi hệ thống tệp và nhanh hơn so với
hệ thống tệp cơ bản
trong một số trường hợp.
Cải thiện hiệu suất truy vấn
Hãy làm theo các phương pháp hay nhất này để cải thiện hiệu suất truy vấn trong SQLite bằng cách giảm thiểu thời gian phản hồi và tối đa hoá hiệu quả xử lý.
Chỉ đọc những hàng cần thiết
Bộ lọc cho phép bạn thu hẹp kết quả của mình bằng cách chỉ định các tiêu chí nhất định, chẳng hạn như phạm vi ngày, vị trí, hoặc tên. Giới hạn cho phép bạn kiểm soát số lượng kết quả bạn thấy:
Kotlin
db.rawQuery(""" SELECT name FROM Customers LIMIT 10; """.trimIndent(), null ).use { cursor -> while (cursor.moveToNext()) { ... } }
Java
try (Cursor cursor = db.rawQuery(""" SELECT name FROM Customers LIMIT 10; """, null)) { while (cursor.moveToNext()) { ... } }
Chỉ đọc những cột cần thiết
Tránh chọn các cột không cần thiết vì có thể làm chậm tốc độ truy vấn và lãng phí tài nguyên. Thay vào đó, chỉ chọn những cột được sử dụng.
Trong ví dụ sau, bạn sẽ chọn id
, name
và phone
:
Kotlin
// This is not the most efficient way of doing this. // See the following example for a better approach. db.rawQuery( """ SELECT id, name, phone FROM customers; """.trimIndent(), null ).use { cursor -> while (cursor.moveToNext()) { val name = cursor.getString(1) // ... } }
Java
// This is not the most efficient way of doing this. // See the following example for a better approach. try (Cursor cursor = db.rawQuery(""" SELECT id, name, phone FROM customers; """, null)) { while (cursor.moveToNext()) { String name = cursor.getString(1); ... } }
Tuy nhiên, bạn chỉ cần cột name
:
Kotlin
db.rawQuery(""" SELECT name FROM Customers; """.trimIndent(), null ).use { cursor -> while (cursor.moveToNext()) { val name = cursor.getString(0) ... } }
Java
try (Cursor cursor = db.rawQuery(""" SELECT name FROM Customers; """, null)) { while (cursor.moveToNext()) { String name = cursor.getString(0); ... } }
Sử dụng DISTINCT
đối với các giá trị duy nhất
Việc sử dụng từ khoá DISTINCT
có thể cải thiện hiệu suất truy vấn bằng cách giảm lượng dữ liệu cần xử lý. Ví dụ: nếu bạn chỉ muốn trả về các giá trị duy nhất từ một cột, hãy sử dụng DISTINCT
:
Kotlin
db.rawQuery(""" SELECT DISTINCT name FROM Customers; """.trimIndent(), null ).use { cursor -> while (cursor.moveToNext()) { // Only iterate over distinct names in Kotlin ... } }
Java
try (Cursor cursor = db.rawQuery(""" SELECT DISTINCT name FROM Customers; """, null)) { while (cursor.moveToNext()) { // Only iterate over distinct names in Java ... } }
Sử dụng các hàm tổng hợp khi có thể
Sử dụng các hàm tổng hợp đối với kết quả tổng hợp mà không cần dữ liệu hàng. Ví dụ: đoạn mã sau đây sẽ kiểm tra xem có ít nhất một hàng phù hợp không:
Kotlin
// This is not the most efficient way of doing this. // See the following example for a better approach. db.rawQuery(""" SELECT id, name FROM Customers WHERE city = 'Paris'; """.trimIndent(), null ).use { cursor -> if (cursor.moveToFirst()) { // At least one customer from Paris ... } else { // No customers from Paris ... }
Java
// This is not the most efficient way of doing this. // See the following example for a better approach. try (Cursor cursor = db.rawQuery(""" SELECT id, name FROM Customers WHERE city = 'Paris'; """, null)) { if (cursor.moveToFirst()) { // At least one customer from Paris ... } else { // No customers from Paris ... } }
Để chỉ tìm nạp hàng đầu tiên, bạn có thể sử dụng EXISTS()
để trả về 0
nếu không có hàng phù hợp và 1
nếu có một hoặc nhiều hàng trùng khớp:
Kotlin
db.rawQuery(""" SELECT EXISTS ( SELECT null FROM Customers WHERE city = 'Paris'; ); """.trimIndent(), null ).use { cursor -> if (cursor.moveToFirst() && cursor.getInt(0) == 1) { // At least one customer from Paris ... } else { // No customers from Paris ... } }
Java
try (Cursor cursor = db.rawQuery(""" SELECT EXISTS ( SELECT null FROM Customers WHERE city = 'Paris' ); """, null)) { if (cursor.moveToFirst() && cursor.getInt(0) == 1) { // At least one customer from Paris ... } else { // No customers from Paris ... } }
Sử dụng các hàm tổng hợp SQLite trong mã lập trình ứng dụng của bạn:
COUNT
: đếm xem có bao nhiêu hàng trong một cột.SUM
: thêm tất cả giá trị bằng số vào cột.MIN
hoặcMAX
: xác định giá trị thấp nhất hoặc cao nhất. Hoạt động với các cột số, loạiDATE
và loại văn bản.AVG
: tìm giá trị số trung bình.GROUP_CONCAT
: nối các chuỗi với dấu phân tách tuỳ chọn.
Sử dụng COUNT()
thay vì Cursor.getCount()
Trong ví dụ sau, hàm Cursor.getCount()
đọc tất cả hàng trong cơ sở dữ liệu và trả về tất cả giá trị hàng:
Kotlin
// This is not the most efficient way of doing this. // See the following example for a better approach. db.rawQuery(""" SELECT id FROM Customers; """.trimIndent(), null ).use { cursor -> val count = cursor.getCount() }
Java
// This is not the most efficient way of doing this. // See the following example for a better approach. try (Cursor cursor = db.rawQuery(""" SELECT id FROM Customers; """, null)) { int count = cursor.getCount(); ... }
Tuy nhiên, bằng cách sử dụng COUNT()
, cơ sở dữ liệu chỉ trả về số đếm:
Kotlin
db.rawQuery(""" SELECT COUNT(*) FROM Customers; """.trimIndent(), null ).use { cursor -> cursor.moveToFirst() val count = cursor.getInt(0) }
Java
try (Cursor cursor = db.rawQuery(""" SELECT COUNT(*) FROM Customers; """, null)) { cursor.moveToFirst(); int count = cursor.getInt(0); ... }
Dùng truy vấn Nest thay vì dùng đoạn mã
SQL có thể kết hợp và hỗ trợ các truy vấn con, tham số kết hợp và quy tắc ràng buộc đối với khoá foreign. Bạn có thể sử dụng kết quả của một truy vấn trong một truy vấn khác mà không xem mã lập trình ứng dụng. Điều này làm giảm nhu cầu sao chép dữ liệu từ SQLite và cho phép công cụ cơ sở dữ liệu tối ưu hoá truy vấn.
Trong ví dụ sau, bạn có thể chạy một truy vấn để tìm xem thành phố nào có nhiều khách hàng nhất, sau đó sử dụng kết quả trong một truy vấn khác để tìm tất cả khách hàng từ thành phố đó:
Kotlin
// This is not the most efficient way of doing this. // See the following example for a better approach. db.rawQuery(""" SELECT city FROM Customers GROUP BY city ORDER BY COUNT(*) DESC LIMIT 1; """.trimIndent(), null ).use { cursor -> if (cursor.moveToFirst()) { val topCity = cursor.getString(0) db.rawQuery(""" SELECT name, city FROM Customers WHERE city = ?; """.trimIndent(), arrayOf(topCity)).use { innerCursor -> while (innerCursor.moveToNext()) { ... } } } }
Java
// This is not the most efficient way of doing this. // See the following example for a better approach. try (Cursor cursor = db.rawQuery(""" SELECT city FROM Customers GROUP BY city ORDER BY COUNT(*) DESC LIMIT 1; """, null)) { if (cursor.moveToFirst()) { String topCity = cursor.getString(0); try (Cursor innerCursor = db.rawQuery(""" SELECT name, city FROM Customers WHERE city = ?; """, new String[] {topCity})) { while (innerCursor.moveToNext()) { ... } } } }
Để nhận được kết quả trong khoảng thời gian bằng phân nửa so với ví dụ trước, hãy sử dụng một truy vấn SQL với các câu lệnh lồng nhau:
Kotlin
db.rawQuery(""" SELECT name, city FROM Customers WHERE city IN ( SELECT city FROM Customers GROUP BY city ORDER BY COUNT (*) DESC LIMIT 1; ); """.trimIndent(), null ).use { cursor -> if (cursor.moveToNext()) { ... } }
Java
try (Cursor cursor = db.rawQuery(""" SELECT name, city FROM Customers WHERE city IN ( SELECT city FROM Customers GROUP BY city ORDER BY COUNT(*) DESC LIMIT 1 ); """, null)) { while(cursor.moveToNext()) { ... } }
Kiểm tra tính duy nhất trong SQL
Nếu không được chèn một hàng, trừ phi một giá trị cột cụ thể là duy nhất trong bảng, thì việc thực thi tính duy nhất đó dưới dạng một quy tắc hạn chế đối với cột có thể hiệu quả hơn.
Trong ví dụ sau, một truy vấn được chạy để xác thực hàng sẽ được chèn và một truy vấn khác thực sự chèn hàng đó vào:
Kotlin
// This is not the most efficient way of doing this. // See the following example for a better approach. db.rawQuery( """ SELECT EXISTS ( SELECT null FROM customers WHERE username = ? ); """.trimIndent(), arrayOf(customer.username) ).use { cursor -> if (cursor.moveToFirst() && cursor.getInt(0) == 1) { throw AddCustomerException(customer) } } db.execSQL( "INSERT INTO customers VALUES (?, ?, ?)", arrayOf( customer.id.toString(), customer.name, customer.username ) )
Java
// This is not the most efficient way of doing this. // See the following example for a better approach. try (Cursor cursor = db.rawQuery(""" SELECT EXISTS ( SELECT null FROM customers WHERE username = ? ); """, new String[] { customer.username })) { if (cursor.moveToFirst() && cursor.getInt(0) == 1) { throw new AddCustomerException(customer); } } db.execSQL( "INSERT INTO customers VALUES (?, ?, ?)", new String[] { String.valueOf(customer.id), customer.name, customer.username, });
Thay vì kiểm tra quy tắc ràng buộc riêng trong Kotlin hoặc Java, bạn có thể kiểm tra quy tắc ràng buộc này trong SQL khi xác định bảng:
CREATE TABLE Customers(
id INTEGER PRIMARY KEY,
name TEXT,
username TEXT UNIQUE
);
SQLite thực hiện tương tự như sau:
CREATE TABLE Customers(...);
CREATE UNIQUE INDEX CustomersUsername ON Customers(username);
Hiện tại, bạn có thể chèn một hàng và để SQLite kiểm tra quy tắc ràng buộc:
Kotlin
try { db.execSql( "INSERT INTO Customers VALUES (?, ?, ?)", arrayOf(customer.id.toString(), customer.name, customer.username) ) } catch(e: SQLiteConstraintException) { throw AddCustomerException(customer, e) }
Java
try { db.execSQL( "INSERT INTO Customers VALUES (?, ?, ?)", new String[] { String.valueOf(customer.id), customer.name, customer.username, }); } catch (SQLiteConstraintException e) { throw new AddCustomerException(customer, e); }
SQLite hỗ trợ các chỉ mục duy nhất với nhiều cột:
CREATE TABLE table(...);
CREATE UNIQUE INDEX unique_table ON table(column1, column2, ...);
SQLite sẽ xác thực các quy tắc ràng buộc nhanh hơn và có mức hao tổn thấp hơn so với mã Kotlin hoặc Java. Bạn nên sử dụng SQLite thay vì mã ứng dụng.
Tạo nhiều lượt chèn trong một giao dịch
Một giao dịch sẽ thực hiện nhiều thao tác, giúp cải thiện không chỉ hiệu quả mà còn cả độ chính xác. Để cải thiện tính nhất quán của dữ liệu và tăng tốc hiệu suất, bạn có thể chèn hàng loạt:
Kotlin
db.beginTransaction() try { customers.forEach { customer -> db.execSql( "INSERT INTO Customers VALUES (?, ?, ...)", arrayOf(customer.id.toString(), customer.name, ...) ) } } finally { db.endTransaction() }
Java
db.beginTransaction(); try { for (customer : Customers) { db.execSQL( "INSERT INTO Customers VALUES (?, ?, ...)", new String[] { String.valueOf(customer.id), customer.name, ... }); } } finally { db.endTransaction() }
Sử dụng công cụ khắc phục sự cố
SQLite cung cấp các công cụ khắc phục sự cố sau đây để giúp đo lường hiệu suất.
Sử dụng lời nhắc tương tác của SQLite
Chạy SQLite trên máy của bạn để chạy truy vấn và tìm hiểu.
Các phiên bản nền tảng Android khác nhau sẽ sử dụng các bản sửa đổi khác nhau của SQLite. Để sử dụng cùng một công cụ trên thiết bị chạy Android, hãy sử dụng adb shell
và chạy sqlite3
trên thiết bị mục tiêu.
Bạn có thể yêu cầu SQLite truy vấn theo thời gian:
sqlite> .timer on
sqlite> SELECT ...
Run Time: real ... user ... sys ...
EXPLAIN QUERY PLAN
Bạn có thể yêu cầu SQLite giải thích ý định trả lời truy vấn bằng cách sử dụng EXPLAIN QUERY PLAN
:
sqlite> EXPLAIN QUERY PLAN
SELECT id, name
FROM Customers
WHERE city = 'Paris';
QUERY PLAN
`--SCAN Customers
Ví dụ trước yêu cầu quét toàn bộ bảng mà không có chỉ mục để tìm tất cả khách hàng sống ở Paris. Đây gọi là độ phức tạp tuyến tính. SQLite cần đọc tất cả hàng và chỉ giữ lại những hàng khớp với khách hàng ở Paris. Để khắc phục điều này, bạn có thể thêm một chỉ mục:
sqlite> CREATE INDEX Idx1 ON Customers(city);
sqlite> EXPLAIN QUERY PLAN
SELECT id, name
FROM Customers
WHERE city = 'Paris';
QUERY PLAN
`--SEARCH test USING INDEX Idx1 (city=?
Nếu đang sử dụng shell tương tác, bạn có thể yêu cầu SQLite luôn giải thích kế hoạch truy vấn:
sqlite> .eqp on
Để biết thêm thông tin, hãy xem phần Lập kế hoạch truy vấn.
Trình phân tích SQLite
SQLite cung cấp
sqlite3_analyzer
giao diện dòng lệnh (CLI) để kết xuất thông tin bổ sung có thể được dùng để
khắc phục sự cố hiệu suất. Để cài đặt, hãy truy cập trang Tải xuống của SQLite.
Bạn có thể sử dụng adb pull
để tải tệp cơ sở dữ liệu từ một thiết bị mục tiêu xuống máy trạm để phân tích:
adb pull /data/data/<app_package_name>/databases/<db_name>.db
Trình duyệt SQLite
Bạn cũng có thể cài đặt công cụ GUI của Trình duyệt SQLite trên trang Tải xuống của SQLite.
Ghi nhật ký Android
Android đếm số lần truy vấn SQLite và ghi lại các truy vấn đó cho bạn:
# Enable query time logging
$ adb shell setprop log.tag.SQLiteTime VERBOSE
# Disable query time logging
$ adb shell setprop log.tag.SQLiteTime ERROR
```### Perfetto tracing
### Perfetto tracing {:#perfetto-tracing}
When [configuring Perfetto](https://perfetto.dev/docs/concepts/config), you may
add the following to include tracks for individual queries:
```protobuf
data_sources {
config {
name: "linux.ftrace"
ftrace_config {
atrace_categories: "database"
}
}
}
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Chạy phép đo điểm chuẩn trong tính năng Tích hợp liên tục
- Khung hình bị treo
- Tạo và đo lường Hồ sơ cơ sở mà không cần Macrobenchmark