<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>分库分表 on 追风笔记</title><link>https://88ok.github.io/tags/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8/</link><description>Recent content in 分库分表 on 追风笔记</description><generator>Hugo</generator><language>zh</language><lastBuildDate>Mon, 15 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://88ok.github.io/tags/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8/index.xml" rel="self" type="application/rss+xml"/><item><title>分库分表策略与热点治理</title><link>https://88ok.github.io/columns/data/sharding-strategy/</link><pubDate>Mon, 30 Mar 2026 00:00:00 +0000</pubDate><guid>https://88ok.github.io/columns/data/sharding-strategy/</guid><description>&lt;p&gt;当单表涨到几亿行、单库连接打满，分库分表就从「可选项」变成「生存项」。但分片一旦定错键，后期重构的代价接近重写。所以策略要在一开始就想清楚。&lt;/p&gt;&#10;&lt;h2 id="分片键是第一步也是最重要的一步"&gt;分片键是第一步，也是最重要的一步&#10;&lt;/h2&gt;&#10;&lt;p&gt;分片键决定数据怎么散、请求怎么走。选错键，要么数据倾斜，要么跨分片查询泛滥。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;选高频等值查询字段&lt;/strong&gt;：比如账户号、客户号，保证大多数请求落单分片。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;避免低基数或单调递增&lt;/strong&gt;：性别这种分片键会制造大分片；自增 ID 做键会集中在最新分片，形成写入热点。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;兼顾关联查询&lt;/strong&gt;：同一客户的账户、交易最好同片，减少跨片 JOIN。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="td-code td-code--untitled" id="td-code-c3928bd6-fence-0" data-td-code data-td-code-auto-id&#10; data-td-language="sql" data-td-line-count="3"&gt;&#10; &lt;div class="td-code__viewport" id="td-code-c3928bd6-fence-0-viewport" data-td-code-viewport&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 按客户号哈希分 1024 片&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trans_$&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cust_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cust_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;trans_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;h2 id="扩容预分片优于临时拆"&gt;扩容：预分片优于临时拆&#10;&lt;/h2&gt;&#10;&lt;p&gt;一开始就按「未来三年规模」定足够多的逻辑分片（如 1024、4096），物理上先少后多。扩容只是把逻辑分片映射到新物理库，&lt;strong&gt;数据迁移量远小于重新分片&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;div class="td-table-scroll td-table-scroll--static"&gt;&#10;&lt;table&gt;&#10; &lt;thead&gt;&#10; &lt;tr&gt;&#10; &lt;th scope="col"&gt;策略&lt;/th&gt;&#10; &lt;th scope="col"&gt;优点&lt;/th&gt;&#10; &lt;th scope="col"&gt;缺点&lt;/th&gt;&#10; &lt;/tr&gt;&#10; &lt;/thead&gt;&#10; &lt;tbody&gt;&#10; &lt;tr&gt;&#10; &lt;td&gt;预分片&lt;/td&gt;&#10; &lt;td&gt;扩容平滑&lt;/td&gt;&#10; &lt;td&gt;初期略冗余&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td&gt;范围分片&lt;/td&gt;&#10; &lt;td&gt;易理解&lt;/td&gt;&#10; &lt;td&gt;易热点&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;tr&gt;&#10; &lt;td&gt;哈希分片&lt;/td&gt;&#10; &lt;td&gt;均衡&lt;/td&gt;&#10; &lt;td&gt;范围查询跨片&lt;/td&gt;&#10; &lt;/tr&gt;&#10; &lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&#10;&lt;div class="td-code td-code--untitled" id="td-code-c3928bd6-fence-1" data-td-code data-td-code-auto-id&#10; data-td-language="java" data-td-line-count="3"&gt;&#10; &lt;div class="td-code__viewport" id="td-code-c3928bd6-fence-1-viewport" data-td-code-viewport&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 逻辑分片到物理库的映射可配置&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;trans_&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;custId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;phys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;routeTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logic&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;映射到具体物理库&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;h2 id="热点治理"&gt;热点治理&#10;&lt;/h2&gt;&#10;&lt;p&gt;即使哈希均匀，业务上仍会有「明星账户」「大商户」成为单点热点。&lt;/p&gt;</description></item><item><title>分库分表不是银弹</title><link>https://88ok.github.io/blog/mysql-sharding/</link><pubDate>Mon, 15 Jun 2026 00:00:00 +0000</pubDate><guid>https://88ok.github.io/blog/mysql-sharding/</guid><description>&lt;p&gt;分库分表在很多团队是一种默认操作：数据量一大就分。但它换来的收益很窄，付出的代价很宽，而且代价大多在上线半年后才开始显现。&lt;/p&gt;&#10;&lt;h2 id="先问要不要分"&gt;先问要不要分&#10;&lt;/h2&gt;&#10;&lt;p&gt;分库分表真正解决的问题只有两个：单表数据量导致的索引效率下降，以及单库写入的 IOPS 瓶颈。除此之外的问题它都解决不了，甚至会恶化。&lt;/p&gt;&#10;&lt;p&gt;在决定分之前，这几件事的性价比更高：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;加索引或改查询&lt;/strong&gt;。慢查询里相当大一部分是索引缺失或者写法导致索引失效，跟数据量无关。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;冷热分离&lt;/strong&gt;。交易流水表里九成查询集中在最近三个月。把历史数据归档到历史库，主表立刻瘦身，成本远低于分表。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;读写分离&lt;/strong&gt;。读多写少的场景加从库就够了。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;升配&lt;/strong&gt;。听起来不体面，但一台高配实例能撑到的量往往超出预期，而且省下的是人力。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;我的经验阈值：单表超过两千万行且增长稳定、或者写入已经打满 IO，才考虑分表。仅仅因为&amp;quot;数据量看着挺大&amp;quot;就分，是给自己找活干。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 id="分片键决定生死"&gt;分片键决定生死&#10;&lt;/h2&gt;&#10;&lt;p&gt;分片键选错基本没法补救——除非停机重新迁移全量数据。&lt;/p&gt;&#10;&lt;p&gt;选择原则是&lt;strong&gt;让高频查询都能带上分片键&lt;/strong&gt;。交易流水表用账号分片，那么&amp;quot;查某账号最近流水&amp;quot;就是单分片查询，性能很好；但&amp;quot;查某商户当天全部流水&amp;quot;就变成了全分片扫描加内存聚合。&lt;/p&gt;&#10;&lt;div class="td-code td-code--untitled" id="td-code-35cd25d1-fence-0" data-td-code data-td-code-auto-id&#10; data-td-language="sql" data-td-line-count="10"&gt;&#10; &lt;div class="td-code__viewport" id="td-code-35cd25d1-fence-0-viewport" data-td-code-viewport&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 单分片，走得很好&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;txn_flow&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;account_no&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6222...1234&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;txn_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2026-06-01&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;txn_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 跨全部分片，聚合在应用层做，分片多了就是灾难&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merchant_no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;txn_flow&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;txn_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2026-06-14&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merchant_no&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;/div&gt;&#10;&lt;p&gt;第二类需求不要靠分片库硬扛，应该走另一条路：同步一份到 OLAP 引擎或数仓。&lt;strong&gt;一份数据满足所有查询模式的想法本身就是问题的根源。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;另外一定要&lt;strong&gt;一次性把逻辑分片数定足&lt;/strong&gt;。我们定了 1024 个逻辑分片映射到 8 个物理库，扩容时只搬分片区间，不用重新哈希。如果直接按物理库取模，第一次扩容就要迁移全量数据。&lt;/p&gt;</description></item></channel></rss>