面试题答案
一键面试查询优化
- 索引使用
- 分析查询语句:仔细查看应用中所有涉及数据库查询的地方,对于频繁查询的字段添加索引。例如,如果经常根据用户ID查询用户信息,就在用户表的用户ID字段上添加索引。
- 复合索引:当多个字段经常同时用于查询条件时,创建复合索引。比如经常根据用户名和用户所在城市查询用户,就可以在用户名和城市字段上创建复合索引。语法在Flutter的SQLite封装中类似
CREATE INDEX idx_user_city ON users (username, city);
- 减少查询字段
- 只查询必要字段:避免使用
SELECT *
,而是明确列出需要的字段。例如,只需要用户的姓名和年龄,就用SELECT name, age FROM users;
,这样可以减少数据传输量,提高查询速度。
- 只查询必要字段:避免使用
- 分页查询
- 限制结果集:对于数据量较大的查询,使用
LIMIT
和OFFSET
进行分页。比如在显示用户列表时,一次只获取20条数据,SELECT * FROM users LIMIT 20 OFFSET 0;
,后续页面通过调整OFFSET
值来获取不同批次的数据。
- 限制结果集:对于数据量较大的查询,使用
连接管理
- 连接池
- 创建连接池:使用连接池来管理数据库连接,避免频繁创建和销毁连接。在Flutter中可以借助第三方库(如
sqflite
库本身在一定程度上支持连接池概念)来实现。连接池维护一定数量的活跃连接,应用需要使用数据库时从连接池中获取连接,使用完毕后归还连接,而不是每次都新建和关闭连接,减少连接建立和销毁的开销。
- 创建连接池:使用连接池来管理数据库连接,避免频繁创建和销毁连接。在Flutter中可以借助第三方库(如
- 连接复用
- 复用已有连接:在应用的生命周期内,尽量复用已经建立的数据库连接。例如,在一个页面内多次操作数据库时,不要每次操作都重新建立连接,而是使用已经打开的连接对象进行操作。
事务处理
- 批量操作
- 使用事务:对于多个相关的数据库操作,将它们放在一个事务中执行。例如,在插入多条用户数据时,将所有插入操作放在一个事务里。在Flutter的SQLite封装中,代码类似如下:
final db = await databaseFactory.openDatabase(databasePath);
await db.transaction((txn) async {
for (var user in userList) {
await txn.rawInsert('INSERT INTO users (name, age) VALUES (?,?)', [user.name, user.age]);
}
});
这样可以减少多次单独操作的开销,提高整体性能。
数据库结构优化
- 范式与反范式平衡
- 遵循范式:数据库设计初期尽量遵循范式,减少数据冗余,保证数据的一致性。例如,在设计订单系统时,订单表和用户表分开,避免在订单表中重复存储用户的详细信息。
- 适当反范式:在某些性能要求较高的场景下,进行适当的反范式化。比如,在统计订单相关信息时,频繁需要用户的基本信息,为了减少表连接操作,可以在订单表中冗余存储部分用户基本信息(如用户名等不经常变化的信息)。
- 表结构优化
- 合理字段类型:选择合适的字段类型,避免过度占用空间。例如,对于表示性别的字段,使用
CHAR(1)
而不是VARCHAR(10)
。对于表示状态的字段,可以使用INTEGER
来存储状态码,而不是使用字符串,这样可以减少存储空间,提高查询效率。
- 合理字段类型:选择合适的字段类型,避免过度占用空间。例如,对于表示性别的字段,使用