尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

HarmonyOS 7 / API 26 RDB 查询变慢怎么查:索引设计、查询条件和 explain 检查怎么拆

HarmonyOS 7 / API 26 RDB 查询变慢怎么查:索引设计、查询条件和 explain 检查怎么拆 HarmonyOS 7 / API 26 RDB 查询变慢怎么查索引设计、查询条件和 explain 检查怎么拆RDB 查询慢很多时候不是数据库本身慢而是查询条件和索引没对上。HarmonyOS 7.0.0 / API 26 项目里如果列表页、搜索页、历史记录页都开始查本地库索引设计就不能靠感觉。这篇只拆一个问题RDB 查询变慢时怎么确认该不该建索引、索引字段顺序怎么定、查询语句有没有真正命中索引。运行环境和检查范围项目取值系统版本HarmonyOS 7.0.0满足 HarmonyOS 5.0.0 及以上范围API 版本API 26工程模型Stage 模型开发语言ArkTS数据能力RDB 本地关系型数据库验证目标查询条件和索引匹配慢查询能被复现和解释问题一般怎么发生坏例子通常是页面查得越来越多但表结构还是最初那一版constsqlSELECT * FROM recipe WHERE category ? AND updated_at ? ORDER BY updated_at DESCconstcursorawaitrdbStore.querySql(sql,[hot,String(lastTime)])如果表里没有合适索引这条查询数据少时没感觉数据一多就会变成全表扫描。用户看到的就是页面打开慢、搜索慢、筛选后列表卡住。先用脚本把坏索引挡住我会先用检查脚本确认四件事有没有索引计划、查询条件是否和索引顺序匹配、有没有 explain 检查、迁移失败能不能回滚。constcases[{name:bad-rdb-index-check,hasIndexPlan:false,verifiesQueryCondition:false,hasExplainCheck:false,hasRollbackPlan:false},{name:good-rdb-index-normal,hasIndexPlan:true,verifiesQueryCondition:true,hasExplainCheck:true,hasRollbackPlan:true},{name:good-rdb-index-boundary,hasIndexPlan:true,verifiesQueryCondition:true,hasExplainCheck:true,hasRollbackPlan:true},];functioninspect(item){consterrors[];if(!item.hasIndexPlan)errors.push(index plan is missing);if(!item.verifiesQueryCondition)errors.push(query condition does not match index);if(!item.hasExplainCheck)errors.push(explain check is missing);if(!item.hasRollbackPlan)errors.push(rollback plan is missing);return{...item,passed:errors.length0,errors};}本地验证结果是 3 个用例里 2 个通过、1 个失败。失败项就是没有索引计划、没有 explain 检查的写法。{total:3,passed:2,failed:1}第一层先从查询场景反推索引不要看到字段就建索引。先看页面到底怎么查。比如常见场景是按分类过滤再按更新时间倒序展示。constlistSqlSELECT id, title, category, updated_at FROM recipe WHERE category ? ORDER BY updated_at DESC LIMIT ? OFFSET ?constargs[hot,20,0]这个查询更适合组合索引先 category再 updated_at。awaitrdbStore.executeSql(CREATE INDEX IF NOT EXISTS idx_recipe_category_updated ON recipe(category, updated_at DESC))字段顺序要跟查询条件贴近。category 是等值过滤updated_at 是排序字段这样组合起来比单独给每个字段建索引更有意义。第二层索引升级也要进迁移索引不是随便启动时建一下就完事。它属于数据库结构的一部分也要跟 schemaVersion 走。asyncfunctionmigrateV2ToV3(rdbStore:relationalStore.RdbStore){awaitrdbStore.beginTransaction()try{awaitrdbStore.executeSql(CREATE INDEX IF NOT EXISTS idx_recipe_category_updated ON recipe(category, updated_at DESC))awaitsaveSchemaVersion(rdbStore,3)awaitrdbStore.commit()}catch(error){awaitrdbStore.rollBack()throwerror}}这样做的好处是索引创建失败不会把版本号错误推进到 v3。下次启动还能继续修复而不是卡在一个假成功状态。第三层用 explain 或查询计划验证建了索引不等于命中了索引。发布前要验证查询计划至少确认关键 SQL 没有继续全表扫描。constexplainSqlEXPLAIN QUERY PLAN SELECT id, title FROM recipe WHERE category ? ORDER BY updated_at DESC LIMIT 20constcursorawaitrdbStore.querySql(explainSql,[hot])while(cursor.goToNextRow()){constdetailcursor.getString(cursor.getColumnIndex(detail))if(detail.includes(SCAN recipe)){thrownewError(recipe query still scans full table)}}cursor.close()如果查询计划里还是 SCAN大概率是索引顺序、查询条件或排序方式没有对上。两个用例怎么验第一个用例是普通分页查询。准备 5000 条数据按分类筛选并按更新时间排序确认查询计划命中组合索引。第二个用例是索引迁移失败。故意让创建索引时抛错确认事务回滚schemaVersion 不能被写成新版本。方案对比方案好处风险发现慢了再随手建索引快字段顺序容易错迁移不可控每个字段都单独建索引看起来全面写入变慢查询未必命中查询场景反推组合索引再用 explain 验证最稳需要补迁移和验证脚本我会选第三种。索引不是越多越好而是要刚好匹配页面的查询方式。最后怎么避免再出问题以后新增列表筛选、搜索、排序时我会同步补三件事关键 SQL、索引迁移、查询计划检查。没有 explain 结果的索引优化只能算猜测不能算真正完成。
返回列表