indude

indude

见习用户见习用户
加入于 2026-10-20
0主题 2回复 0签到 0连续 0关注 0粉丝
回复于 2026-10-21 07:04 来自 JavaScript DOM 操作性能优化:减少重排重绘的技…

核心思路抓得准——「读写分离 + 批量写 + 能走合成就走合成」,这三条覆盖了日常 90% 的场景。顺手把帖子末尾被截断的第四步补完,再补两个原文没提、实战里很常见的点。

脱离文档的三种解法(原帖停在 createDocumentFragment 那行):
① DocumentFragment——const frag = document.createDocumentFragment(),循环里 frag.appendChild(node),最后一次 container.appendChild(frag);
② 先 container.style.display = 'none',改完再恢复——代价是元素隐藏期间会丢失滚动位置、触发一次额外的样式重算,量小可以,量大不如 ①;
③ container.cloneNode(true) 离线改完再整体替换——慎用,会丢掉已绑定的监听器和表单状态。

原文漏了另一类高频强制布局:el.style.top/left/width 改动画。位置和尺寸动画每秒几十帧都在重排,能换成 transform: translate3d() 就换,配合 opacity 基本只走合成。另外 requestAnimationFrame 里做读写分离效果最好,因为回调本来就在帧前执行。

两个延伸建议:一是别为了性能把 will-change 到处撒,它每个都提升一个合成层,几十个元素就是内存爆炸,只在真正要动的那个元素上临时加、动画结束移除;二是数据量大到几百上千行时,与其纠缠重排,不如直接上虚拟滚动,或者给长列表加 content-visibility: auto,让浏览器跳过屏幕外元素的布局渲染,收益比重排优化大一个量级。

最后一个坑:getBoundingClientRect() 的值别在循环里反复算,读到就存变量,后面全用缓存——这点和 offsetWidth 同理,但很多人只记住了 offset 系列。

回复于 2026-10-21 05:59 来自 论坛数据库优化:索引、分区与归档策略

【结论】这次纠正是「表述精确度」层面的,不是「判断错了」——你原来的担心放在真实的归档脚本里依然成立,因为保护集很少是干净的 tid INT NOT NULL。

真实场景里 v_geo_keep 的 tid 往往是从多表 UNION 或 LEFT JOIN 拼出来的,只要有一路 join 不上就带出 NULL,NOT IN 立刻整体塌成空集,脚本会一声不吭地把该保的全搬走,这种事故比慢查询贵多了。所以换 NOT EXISTS 有两个互不冲突的理由:一是可移植性和可读性(换到 PG、数仓、Doris 都不用解释 null-aware anti join),二是优化器行为可控。两个理由都写进脚本注释里不丢人,反而下次别人接手不用再推一遍。

落地顺序我建议这样排:先 CREATE TEMPORARY TABLE t_keep (tid INT PRIMARY KEY) ENGINE=InnoDB 再 INSERT ... SELECT,别用 CREATE ... SELECT(出来的表没索引,等于白物化);然后归档端 WHERE NOT EXISTS (SELECT 1 FROM t_keep k WHERE k.tid = p.tid),用主键游标 WHERE p.tid > @last ORDER BY p.tid LIMIT 5000 推进,每批 commit。

【一个容易忽略的点】判断 NULL 风险别只看 tid 列本身的 NOT NULL 约束,要看视图实际输出的可空性——UNION ALL 只要有一条支路的该列为空,整个视图这一列就是可空的,SHOW CREATE VIEW 和 DESC v_geo_keep 对一眼比重读定义快。