<?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://xiaobox.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/</link><description>Recent content in 数据库 on 小盒子的技术分享</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sun, 01 Jun 2025 04:03:27 +0000</lastBuildDate><atom:link href="https://xiaobox.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/index.xml" rel="self" type="application/rss+xml"/><item><title>Milvus 向量数据库快速入门（人话版）</title><link>https://xiaobox.github.io/p/2025-06-01-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men-ren-hua-ban/</link><pubDate>Sun, 01 Jun 2025 04:03:27 +0000</pubDate><guid>https://xiaobox.github.io/p/2025-06-01-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men-ren-hua-ban/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-06-01-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men-ren-hua-ban/cover.jpg" alt="Featured image of post Milvus 向量数据库快速入门（人话版）" /&gt;&lt;h2 id="milvus-到底是干嘛的"&gt;&lt;a href="#milvus-%e5%88%b0%e5%ba%95%e6%98%af%e5%b9%b2%e5%98%9b%e7%9a%84" class="header-anchor"&gt;&lt;/a&gt;Milvus 到底是干嘛的？
&lt;/h2&gt;&lt;p&gt;它是“给向量找对象”的超高速数据库——存向量、比相似、返回前 K 名。&lt;/p&gt;
&lt;p&gt;Milvus 就是给「向量」找对象的数据库——它能帮你把一堆高维向量存好、管好、飞快地按“相似度”把最像的几条挑出来。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;和普通数据库比，Milvus天生会“模糊配对”，不是 exact match 而是“谁更像”。&lt;/li&gt;
&lt;li&gt;内核走的是“先分桶/建图，再局部暴力”，所以大规模也能搜得飞快。&lt;/li&gt;
&lt;li&gt;2.x 版本把「数据落盘」「分布式容灾」都外包给 RocksDB + MinIO + etcd——省了你很多心。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="先认几个关键词"&gt;&lt;a href="#%e5%85%88%e8%ae%a4%e5%87%a0%e4%b8%aa%e5%85%b3%e9%94%ae%e8%af%8d" class="header-anchor"&gt;&lt;/a&gt;先认几个关键词
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-06-01-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men-ren-hua-ban/001-c2fdff5a.png"&gt;&lt;/p&gt;
&lt;h2 id="部署使用"&gt;&lt;a href="#%e9%83%a8%e7%bd%b2%e4%bd%bf%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;部署使用
&lt;/h2&gt;&lt;p&gt;五步跑通「单机体验」+ 三步升级「小集群」&lt;/p&gt;
&lt;h3 id="单机-5-步"&gt;&lt;a href="#%e5%8d%95%e6%9c%ba-5-%e6%ad%a5" class="header-anchor"&gt;&lt;/a&gt;单机 5 步
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;拉镜像 docker run milvusdb/milvus:v2.4.3&lt;/li&gt;
&lt;li&gt;建楼 create_collection()——确定字段维度、主键、向量字段。&lt;/li&gt;
&lt;li&gt;搬人 insert() → flush()。&lt;/li&gt;
&lt;li&gt;装电梯 create_index()；小数据直接 FLAT，大数据先 IVF，再视情况换 HNSW。&lt;/li&gt;
&lt;li&gt;开门找人 load() → search()/query()；用完可 release().&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="变成-3-节点小集群"&gt;&lt;a href="#%e5%8f%98%e6%88%90-3-%e8%8a%82%e7%82%b9%e5%b0%8f%e9%9b%86%e7%be%a4" class="header-anchor"&gt;&lt;/a&gt;变成 3 节点小集群
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-06-01-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men-ren-hua-ban/002-c0911d8c.png"&gt;&lt;/p&gt;
&lt;h2 id="最常用的-5-步操作"&gt;&lt;a href="#%e6%9c%80%e5%b8%b8%e7%94%a8%e7%9a%84-5-%e6%ad%a5%e6%93%8d%e4%bd%9c" class="header-anchor"&gt;&lt;/a&gt;最常用的 5 步操作
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;建楼：create collection，把字段都定义好&lt;/li&gt;
&lt;li&gt;搬人：insert，把向量和元信息塞进去；记得 flush() 真正落盘&lt;/li&gt;
&lt;li&gt;装电梯：create index，选对索引类型，未来搜索才快&lt;/li&gt;
&lt;li&gt;请保安开门：load，没 load 就像门锁着，啥也搜不到&lt;/li&gt;
&lt;li&gt;找人：search（可加条件 expr），或者只按字段 query&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="索引怎么挑"&gt;&lt;a href="#%e7%b4%a2%e5%bc%95%e6%80%8e%e4%b9%88%e6%8c%91" class="header-anchor"&gt;&lt;/a&gt;索引怎么挑？
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-06-01-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men-ren-hua-ban/003-0a75133a.png"&gt;&lt;/p&gt;
&lt;h2 id="索引调优口诀"&gt;&lt;a href="#%e7%b4%a2%e5%bc%95%e8%b0%83%e4%bc%98%e5%8f%a3%e8%af%80" class="header-anchor"&gt;&lt;/a&gt;索引调优口诀
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;小样本先 FLAT 做 baseline——它慢但最准，方便肉眼看 Recall。&lt;/li&gt;
&lt;li&gt;百 万级优先 IVF_FLAT：调 nlist=√N 起步；提高 nprobe 越准越慢。&lt;/li&gt;
&lt;li&gt;千万级冲 HNSW：关键参 M (边数) 和 efConstruction (建图宽度)，调高两倍能大幅增 Recall。&lt;/li&gt;
&lt;li&gt;超高并发记得“机＋内存”一起扩——索引放内存，多副本才分摊 QPS。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="别踩这些坑-"&gt;&lt;a href="#%e5%88%ab%e8%b8%a9%e8%bf%99%e4%ba%9b%e5%9d%91-" class="header-anchor"&gt;&lt;/a&gt;别踩这些坑 💡
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;向量维度要统一：128 就全 128，别混着来。&lt;/li&gt;
&lt;li&gt;插完别忘 flush：不 flush 就像东西放购物车没结账，搜索不到。&lt;/li&gt;
&lt;li&gt;没 load 就搜索：会报错，先 load()。&lt;/li&gt;
&lt;li&gt;内存不够全加载：用 Partition，分批 load()。&lt;/li&gt;
&lt;li&gt;精度不满意：调 nprobe（IVF）或换 HNSW 试试。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="十大踩坑--急救方案"&gt;&lt;a href="#%e5%8d%81%e5%a4%a7%e8%b8%a9%e5%9d%91--%e6%80%a5%e6%95%91%e6%96%b9%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;十大踩坑 + 急救方案
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-06-01-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men-ren-hua-ban/004-d5e81d65.png"&gt;&lt;/p&gt;
&lt;h2 id="再进阶一点点"&gt;&lt;a href="#%e5%86%8d%e8%bf%9b%e9%98%b6%e4%b8%80%e7%82%b9%e7%82%b9" class="header-anchor"&gt;&lt;/a&gt;再进阶一点点
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Hybrid Search：边比向量相似度，边过滤价格 &amp;lt; 500 这种条件，SQL 味道更浓。&lt;/li&gt;
&lt;li&gt;一致性模式：默认够用；真要跨机房强一致性就选 Strong。&lt;/li&gt;
&lt;li&gt;持久化：Milvus 本身用 RocksDB ＋ MinIO 存数据，你不用操心怎么落盘。&lt;/li&gt;
&lt;li&gt;与 RAG 的关系：大模型把文本→向量，Milvus 负责“最近邻检索”，再把查到的文档喂回模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="跟其它工具怎么配"&gt;&lt;a href="#%e8%b7%9f%e5%85%b6%e5%ae%83%e5%b7%a5%e5%85%b7%e6%80%8e%e4%b9%88%e9%85%8d" class="header-anchor"&gt;&lt;/a&gt;跟其它工具怎么配？
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;LangChain / LlamaIndex：把 Milvus VectorStore 接进去即可，RAG 极速上线。&lt;/li&gt;
&lt;li&gt;Spark / Flink：批量离线写入 Milvus；确保分批 1 万条以内避免 RPC 超时。&lt;/li&gt;
&lt;li&gt;Airflow：定时 ETL → Embedding → Milvus；flush、compact 都能写成 task。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="到底需要多大机器粗算公式"&gt;&lt;a href="#%e5%88%b0%e5%ba%95%e9%9c%80%e8%a6%81%e5%a4%9a%e5%a4%a7%e6%9c%ba%e5%99%a8%e7%b2%97%e7%ae%97%e5%85%ac%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;“到底需要多大机器？”——粗算公式
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;内存 ≈ （向量维度 × 4 bytes × 向量条数 × 1.4 倍索引系数）﹢ 元数据大小&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;例：1 亿条 768 维 → 768×4×1e8×1.4 ≈ 430 GB（得至少 512 GB 机器，或分区加载）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;硬盘 ≈ 内存 × 1.2（索引 + RocksDB + 日志）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;512G 内存看起来有点儿夸张，所以如果内存吃紧，可以参考以下方法进行优化：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-06-01-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men-ren-hua-ban/005-35ceb743.png"&gt;&lt;/p&gt;
&lt;h2 id="python-端到端-demo-含增删改查"&gt;&lt;a href="#python-%e7%ab%af%e5%88%b0%e7%ab%af-demo-%e5%90%ab%e5%a2%9e%e5%88%a0%e6%94%b9%e6%9f%a5" class="header-anchor"&gt;&lt;/a&gt;Python 端到端 Demo （含增删改查）
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pymilvus&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;utility&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CollectionSchema&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;np&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;connections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;19530&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. 建楼（如果已存在就删掉重建）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;utility&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;demo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;utility&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;demo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CollectionSchema&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INT64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_primary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auto_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FLOAT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;emb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FLOAT_VECTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;demo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. 插 10 条数据&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;titles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;商品&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;19&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;20&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;vecs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;21&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;titles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vecs&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;22&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;23&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 3. 建 IVF 索引 &amp;amp; 加载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;24&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;emb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;index_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;IVF_FLAT&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;metric_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;L2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;params&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;nlist&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;25&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;26&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;27&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 4. 搜索 + 过滤价格 &amp;lt; 50&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;28&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;qv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;29&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;emb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;metric_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;L2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;params&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;nprobe&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;price &amp;lt; 50&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;30&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;([(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;31&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;32&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 5. 删除一条，再查&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;33&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;del_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;34&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id in [&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;del_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&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;</description></item><item><title>Milvus 向量数据库快速入门</title><link>https://xiaobox.github.io/p/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/</link><pubDate>Sat, 31 May 2025 07:47:05 +0000</pubDate><guid>https://xiaobox.github.io/p/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/cover.jpg" alt="Featured image of post Milvus 向量数据库快速入门" /&gt;&lt;h2 id="一什么是-milvus"&gt;&lt;a href="#%e4%b8%80%e4%bb%80%e4%b9%88%e6%98%af-milvus" class="header-anchor"&gt;&lt;/a&gt;一、什么是 Milvus？
&lt;/h2&gt;&lt;p&gt;Milvus 是一款开源的向量数据库，用于存储、管理和检索高维向量数据。它适合构建各种 AI 场景下的向量检索系统，如推荐、图像搜索、问答系统等。&lt;/p&gt;
&lt;h3 id="概念关系图逻辑结构"&gt;&lt;a href="#%e6%a6%82%e5%bf%b5%e5%85%b3%e7%b3%bb%e5%9b%be%e9%80%bb%e8%be%91%e7%bb%93%e6%9e%84" class="header-anchor"&gt;&lt;/a&gt;概念关系图（逻辑结构）
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;Milvus数据库
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;├── Collection集合
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;│ ├── Partition分区
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt;│ │ └── Entity实体
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt;│ │ └── Fields字段（向量 + 元数据）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&gt;│ ├── Schema结构
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;7&lt;/span&gt;&lt;span class="cl"&gt;│ └── Index索引
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;8&lt;/span&gt;&lt;span class="cl"&gt;├── 查询操作（Search / Query）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;9&lt;/span&gt;&lt;span class="cl"&gt;└── 数据一致性机制
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="二milvus-核心概念速查表"&gt;&lt;a href="#%e4%ba%8cmilvus-%e6%a0%b8%e5%bf%83%e6%a6%82%e5%bf%b5%e9%80%9f%e6%9f%a5%e8%a1%a8" class="header-anchor"&gt;&lt;/a&gt;二、Milvus 核心概念速查表
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/001-35c4e3b4.png"&gt;&lt;/p&gt;
&lt;h3 id="实体-entity-示例"&gt;&lt;a href="#%e5%ae%9e%e4%bd%93-entity-%e7%a4%ba%e4%be%8b" class="header-anchor"&gt;&lt;/a&gt;实体 Entity 示例
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;embedding&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;iPhone&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;999.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&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;h2 id="三核心操作流程"&gt;&lt;a href="#%e4%b8%89%e6%a0%b8%e5%bf%83%e6%93%8d%e4%bd%9c%e6%b5%81%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;三、核心操作流程
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/002-62886a11.png"&gt;&lt;/p&gt;
&lt;h2 id="四一致性模型与数据安全保障"&gt;&lt;a href="#%e5%9b%9b%e4%b8%80%e8%87%b4%e6%80%a7%e6%a8%a1%e5%9e%8b%e4%b8%8e%e6%95%b0%e6%8d%ae%e5%ae%89%e5%85%a8%e4%bf%9d%e9%9a%9c" class="header-anchor"&gt;&lt;/a&gt;四、一致性模型与数据安全保障
&lt;/h2&gt;&lt;p&gt;Milvus 提供以下一致性保证：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/003-2ccb64a4.png"&gt;&lt;/p&gt;
&lt;h2 id="五索引类型选择指南"&gt;&lt;a href="#%e4%ba%94%e7%b4%a2%e5%bc%95%e7%b1%bb%e5%9e%8b%e9%80%89%e6%8b%a9%e6%8c%87%e5%8d%97" class="header-anchor"&gt;&lt;/a&gt;五、索引类型选择指南
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/004-f597ad1c.png"&gt;&lt;/p&gt;
&lt;h2 id="六进阶知识点补充"&gt;&lt;a href="#%e5%85%ad%e8%bf%9b%e9%98%b6%e7%9f%a5%e8%af%86%e7%82%b9%e8%a1%a5%e5%85%85" class="header-anchor"&gt;&lt;/a&gt;六、进阶知识点补充
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/005-004e8cb6.png"&gt;&lt;/p&gt;
&lt;h2 id="七实战使用-python-sdk-完整示例基于-milvus-2x"&gt;&lt;a href="#%e4%b8%83%e5%ae%9e%e6%88%98%e4%bd%bf%e7%94%a8-python-sdk-%e5%ae%8c%e6%95%b4%e7%a4%ba%e4%be%8b%e5%9f%ba%e4%ba%8e-milvus-2x" class="header-anchor"&gt;&lt;/a&gt;七、实战：使用 Python SDK 完整示例（基于 Milvus 2.x）
&lt;/h2&gt;&lt;h3 id="环境准备"&gt;&lt;a href="#%e7%8e%af%e5%a2%83%e5%87%86%e5%a4%87" class="header-anchor"&gt;&lt;/a&gt;环境准备
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;pip install pymilvus
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="初始化连接"&gt;&lt;a href="#%e5%88%9d%e5%a7%8b%e5%8c%96%e8%bf%9e%e6%8e%a5" class="header-anchor"&gt;&lt;/a&gt;初始化连接
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pymilvus&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;connections&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;connections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alias&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;19530&amp;#34;&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;h3 id="创建-collection"&gt;&lt;a href="#%e5%88%9b%e5%bb%ba-collection" class="header-anchor"&gt;&lt;/a&gt;创建 Collection
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pymilvus&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CollectionSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;fields&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;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INT64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_primary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auto_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FieldSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;embedding&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DataType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FLOAT_VECTOR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CollectionSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;商品向量集合&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;product_vectors&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema&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;h3 id="插入数据"&gt;&lt;a href="#%e6%8f%92%e5%85%a5%e6%95%b0%e6%8d%ae" class="header-anchor"&gt;&lt;/a&gt;插入数据
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;np&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;titles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;iPhone&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;MacBook&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;AirPods&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;vectors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;titles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vectors&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&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;h3 id="创建索引--加载数据"&gt;&lt;a href="#%e5%88%9b%e5%bb%ba%e7%b4%a2%e5%bc%95--%e5%8a%a0%e8%bd%bd%e6%95%b0%e6%8d%ae" class="header-anchor"&gt;&lt;/a&gt;创建索引 &amp;amp; 加载数据
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;index_params&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;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;index_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;IVF_FLAT&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;metric_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;L2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;params&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;nlist&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;embedding&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;index_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&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;h3 id="向量搜索--条件过滤hybrid-search"&gt;&lt;a href="#%e5%90%91%e9%87%8f%e6%90%9c%e7%b4%a2--%e6%9d%a1%e4%bb%b6%e8%bf%87%e6%bb%a4hybrid-search" class="header-anchor"&gt;&lt;/a&gt;向量搜索 + 条件过滤（Hybrid Search）
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;query_vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tolist&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;search_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;metric_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;L2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;params&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;nprobe&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query_vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;anns_field&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;embedding&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;search_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;expr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;title like &amp;#39;Mac%&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;id: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, distance: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&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;h2 id="八常见踩坑提醒"&gt;&lt;a href="#%e5%85%ab%e5%b8%b8%e8%a7%81%e8%b8%a9%e5%9d%91%e6%8f%90%e9%86%92" class="header-anchor"&gt;&lt;/a&gt;八、常见踩坑提醒
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/006-61fc6e51.png"&gt;&lt;/p&gt;
&lt;h2 id="九真实应用场景参考电商推荐系统"&gt;&lt;a href="#%e4%b9%9d%e7%9c%9f%e5%ae%9e%e5%ba%94%e7%94%a8%e5%9c%ba%e6%99%af%e5%8f%82%e8%80%83%e7%94%b5%e5%95%86%e6%8e%a8%e8%8d%90%e7%b3%bb%e7%bb%9f" class="header-anchor"&gt;&lt;/a&gt;九、真实应用场景参考：电商推荐系统
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-05-31-milvus-xiang-liang-shu-ju-ku-kuai-su-ru-men/007-36f7a9d6.png"&gt;&lt;/p&gt;
&lt;h2 id="十快速上手建议"&gt;&lt;a href="#%e5%8d%81%e5%bf%ab%e9%80%9f%e4%b8%8a%e6%89%8b%e5%bb%ba%e8%ae%ae" class="header-anchor"&gt;&lt;/a&gt;十、快速上手建议
&lt;/h2&gt;&lt;p&gt;✅ 推荐&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从创建 Collection 开始，理解字段与向量的对应关系&lt;/li&gt;
&lt;li&gt;一步步插入数据、构建索引、执行搜索&lt;/li&gt;
&lt;li&gt;多关注向量维度、索引类型和内存管理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;❌ 避免&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向量维度不统一&lt;/li&gt;
&lt;li&gt;未加载数据就开始搜索&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>数据库选型终极指南：从数据类型到应用场景，一篇就够了</title><link>https://xiaobox.github.io/p/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/</link><pubDate>Fri, 14 Mar 2025 09:19:52 +0000</pubDate><guid>https://xiaobox.github.io/p/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/cover.jpg" alt="Featured image of post 数据库选型终极指南：从数据类型到应用场景，一篇就够了" /&gt;&lt;h2 id="引言"&gt;&lt;a href="#%e5%bc%95%e8%a8%80" class="header-anchor"&gt;&lt;/a&gt;引言
&lt;/h2&gt;&lt;p&gt;在当今的数字化时代，数据已成为企业和组织的核心资产。无论是金融交易记录、社交媒体互动、物联网传感器数据，还是企业内部的业务流程信息，都需要通过数据库进行存储、管理和分析。然而，面对市场上数十种主流的数据库技术（如 MySQL、MongoDB、Elasticsearch、HBase、Hive等），如何选择适合自身业务需求的数据库系统，成为许多技术决策者面临的难题。本文将深入探讨数据库的核心分类、技术特性、应用场景以及选择策略，帮助读者构建系统化的选型框架。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="数据库的分类"&gt;&lt;a href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e7%9a%84%e5%88%86%e7%b1%bb" class="header-anchor"&gt;&lt;/a&gt;数据库的分类
&lt;/h2&gt;&lt;p&gt;在进行数据库的选择前，你需要至少知道它的&lt;strong&gt;分类&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在数据库技术的演进过程中，数据存储模型和应用需求的多样性催生了不同类型的数据库系统。这些系统根据其核心设计理念、数据组织方式以及适用场景的差异，形成了多个分类。&lt;/p&gt;
&lt;h3 id="关系型数据库rdbms结构化数据的基石"&gt;&lt;a href="#%e5%85%b3%e7%b3%bb%e5%9e%8b%e6%95%b0%e6%8d%ae%e5%ba%93rdbms%e7%bb%93%e6%9e%84%e5%8c%96%e6%95%b0%e6%8d%ae%e7%9a%84%e5%9f%ba%e7%9f%b3" class="header-anchor"&gt;&lt;/a&gt;关系型数据库（RDBMS）：结构化数据的基石
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;关系型数据库的根基是关系代数和集合论&lt;/strong&gt;，通过二维表（Table）组织数据。每个表由行（记录）和列（字段）构成，通过主键（Primary Key）唯一标识记录，外键（Foreign Key）实现表间的关联。其核心优势在于ACID事务支持，即原子性（Atomicity）、一致性（Consistency）、隔离性（Isolation）、持久性（Durability），适用于对数据一致性要求极高的场景（如金融交易）&lt;/p&gt;
&lt;p&gt;适用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要强一致性的业务系统（银行核心系统、ERP）。&lt;/li&gt;
&lt;li&gt;多表关联查询频繁的OLTP（联机事务处理）场景（电商订单管理）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;局限性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表结构预定义，修改成本高（如新增字段需 ALTER TABLE）。&lt;/li&gt;
&lt;li&gt;水平扩展困难，分库分表复杂度高（需处理分布式事务和跨分片查询）。&lt;/li&gt;
&lt;li&gt;不适合存储半结构化数据（如JSON文档、嵌套数组）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代表数据库：&lt;code&gt;MySQL&lt;/code&gt;、&lt;code&gt;PostgreSQL&lt;/code&gt;、&lt;code&gt;Oracle&lt;/code&gt;、&lt;code&gt;SQL Server&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="nosql-数据库灵活性与扩展性的革命"&gt;&lt;a href="#nosql-%e6%95%b0%e6%8d%ae%e5%ba%93%e7%81%b5%e6%b4%bb%e6%80%a7%e4%b8%8e%e6%89%a9%e5%b1%95%e6%80%a7%e7%9a%84%e9%9d%a9%e5%91%bd" class="header-anchor"&gt;&lt;/a&gt;NoSQL 数据库：灵活性与扩展性的革命
&lt;/h3&gt;&lt;p&gt;NoSQL（Not Only SQL）的诞生是为了解决关系型数据库在扩展性、灵活性和高性能场景下的不足。根据数据模型的差异，NoSQL 可进一步细分为四类：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 文档型数据库（Document Database）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数据模型：以文档为基本单元，通常采用JSON或BSON格式存储，支持嵌套结构和动态字段&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;张三&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;orders&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;order_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;amount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;150.0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;order_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2002&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;amount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;300.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;8&lt;/span&gt;&lt;span class="cl"&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;p&gt;查询能力：支持基于文档属性的查询，部分数据库（如MongoDB）提供类SQL的聚合管道（Aggregation Pipeline）和索引优化。&lt;/p&gt;
&lt;p&gt;适用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;内容管理系统（CMS）中文章的多版本存储。&lt;/li&gt;
&lt;li&gt;用户配置文件的动态字段管理（如社交平台用户的个性化标签）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;局限性：跨文档事务支持较弱（MongoDB 4.0后支持多文档事务，但性能损耗较大）。&lt;/p&gt;
&lt;p&gt;代表数据库：&lt;code&gt;MongoDB&lt;/code&gt;、&lt;code&gt;Couchbase&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 键值型数据库（Key-Value Store）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数据模型：最简单的 NoSQL 模型，数据以键值对（Key-Value）形式存储，Value可以是任意二进制数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;Key: &amp;#34;user:101:profile&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;Value: &amp;#34;{&amp;#39;name&amp;#39;: &amp;#39;李四&amp;#39;, &amp;#39;last_login&amp;#39;: &amp;#39;2023-10-01&amp;#39;}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;高性能特性：通过哈希表实现O(1)时间复杂度的读写操作，适合缓存和高并发场景。&lt;/p&gt;
&lt;p&gt;适用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;会话存储（Session Storage）：快速存取用户登录状态。&lt;/li&gt;
&lt;li&gt;分布式缓存（如Redis缓存热门商品信息）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;局限性：缺乏复杂查询能力（仅能通过Key检索），需业务层处理数据关联逻辑。&lt;/p&gt;
&lt;p&gt;代表数据库：&lt;code&gt;Redis&lt;/code&gt;、&lt;code&gt;Memcached&lt;/code&gt;、&lt;code&gt;Amazon DynamoDB&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 列族数据库（Wide-Column Store）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数据模型：数据按列族（Column Family）组织，每行可动态添加列，适合稀疏矩阵存储。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;Row Key: &amp;#34;device_001&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;Columns: 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &amp;#34;metrics:temperature&amp;#34; -&amp;gt; 25.5
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &amp;#34;metrics:humidity&amp;#34; -&amp;gt; 60%
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt; &amp;#34;location:city&amp;#34; -&amp;gt; &amp;#34;北京&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;存储优势：基于LSM树（Log-Structured Merge Tree）的存储引擎，优化高吞吐写入（如日志、传感器数据）。&lt;/p&gt;
&lt;p&gt;适用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;时间序列数据（物联网设备监控）。&lt;/li&gt;
&lt;li&gt;海量数据的随机读写（如HBase存储网页爬虫数据）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;局限性：复杂查询需依赖Row Key设计，二级索引支持有限。&lt;/p&gt;
&lt;p&gt;代表数据库：&lt;code&gt;Apache HBase&lt;/code&gt;、&lt;code&gt;Cassandra&lt;/code&gt;、&lt;code&gt;Google Bigtable&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 图数据库（Graph Database）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数据模型：以图论为基础，通过节点（Node）、边（Edge）、属性（Property）表示实体及其关系。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;Node: User(id=101, name=&amp;#34;王五&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;Edge: User101 -[FRIEND]-&amp;gt; User102 (since=2020)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查询优势：专为关系查询优化，可高效遍历多跳关系（如社交网络的六度分隔理论）。&lt;/p&gt;
&lt;p&gt;适用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;社交网络中的好友推荐。&lt;/li&gt;
&lt;li&gt;欺诈检测（识别异常交易环路）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;局限性：非关系场景下性能无明显优势，学习曲线陡峭。&lt;/p&gt;
&lt;p&gt;代表数据库：&lt;code&gt;Neo4j&lt;/code&gt;、&lt;code&gt;Amazon Neptune&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="大数据生态数据库分布式与批量处理的支柱"&gt;&lt;a href="#%e5%a4%a7%e6%95%b0%e6%8d%ae%e7%94%9f%e6%80%81%e6%95%b0%e6%8d%ae%e5%ba%93%e5%88%86%e5%b8%83%e5%bc%8f%e4%b8%8e%e6%89%b9%e9%87%8f%e5%a4%84%e7%90%86%e7%9a%84%e6%94%af%e6%9f%b1" class="header-anchor"&gt;&lt;/a&gt;大数据生态数据库：分布式与批量处理的支柱
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;1. 分布式列式存储（HBase）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;技术架构：基于HDFS的分布式存储，通过Region分片实现水平扩展，ZooKeeper协调元数据。&lt;/p&gt;
&lt;p&gt;核心能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;随机实时读写（毫秒级延迟）。&lt;/li&gt;
&lt;li&gt;稀疏数据的高效存储（空值不占空间）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适用场景：实时查询TB级数据（如电信通话记录检索）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 数据仓库（Hive）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;技术原理：将结构化数据映射为HDFS文件，通过 HiveQL（类SQL）转换为MapReduce或Tez任务。&lt;/p&gt;
&lt;p&gt;核心能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;离线批量处理（小时级延迟）。&lt;/li&gt;
&lt;li&gt;复杂ETL流程（数据清洗、转换）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适用场景：历史数据报表生成（如零售业月度销售分析）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 实时数仓（ClickHouse、Doris）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;技术突破：向量化执行引擎、列式存储、预聚合，实现亚秒级响应。&lt;/p&gt;
&lt;p&gt;适用场景：交互式OLAP分析（如广告投放效果实时看板）。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/001-609ddd79.png"&gt;&lt;/p&gt;
&lt;h3 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h3&gt;&lt;p&gt;我们做一个整体的对比&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/002-4df3e69a.png"&gt;&lt;/p&gt;
&lt;p&gt;随着技术发展，数据库的界限逐渐模糊。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多模型数据库：如PostgreSQL通过扩展支持JSONB（文档模型）和Citus（分布式能力）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HTAP&lt;/code&gt;(Hybrid Transactional/Analytical Processing)数据库：TiDB、Oracle Exadata支持OLTP与OLAP混合负载。&lt;/li&gt;
&lt;li&gt;AI驱动数据库：利用机器学习优化查询计划（如Google AlloyDB）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;随着 AI 技术的兴起，&lt;code&gt;向量数据库&lt;/code&gt;也是非常热门的一类数据库。数据库的分类也并非绝对的技术壁垒，而是反映了不同场景下的核心矛盾权衡：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结构化 vs 灵活性&lt;/strong&gt;：关系型牺牲灵活性换取严格约束，文档型反之。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一致性 vs 扩展性&lt;/strong&gt;：CP系统（如ZooKeeper）优先保障一致性，AP系统（如Cassandra）优先保障可用性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时性 vs 吞吐量&lt;/strong&gt;：HBase优化单点查询延迟，Hive优化批量吞吐量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;理解这些分类背后的哲学，才能避免“技术选型中的锤子效应”（手里只有一把锤子，看所有问题都是钉子），从而在复杂业务场景中构建合理的数据存储架构。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="数据类型"&gt;&lt;a href="#%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b" class="header-anchor"&gt;&lt;/a&gt;数据类型
&lt;/h2&gt;&lt;p&gt;在进行数据库的选择前，你要处理的数据类型是你必须要明确的。&lt;/p&gt;
&lt;p&gt;结构化、半结构化和非结构化数据在存储、查询和处理方式上存在本质差异，直接影响了技术选型的路径。&lt;/p&gt;
&lt;p&gt;在数据管理的实践中，数据类型是决定数据库选型的关键因素之一。结构化、半结构化和非结构化数据在存储、查询和处理方式上存在本质差异，直接影响了技术选型的路径。以下从数据特征、处理需求到典型数据库选择展开系统性分析。&lt;/p&gt;
&lt;h3 id="结构化数据秩序与约束的领域"&gt;&lt;a href="#%e7%bb%93%e6%9e%84%e5%8c%96%e6%95%b0%e6%8d%ae%e7%a7%a9%e5%ba%8f%e4%b8%8e%e7%ba%a6%e6%9d%9f%e7%9a%84%e9%a2%86%e5%9f%9f" class="header-anchor"&gt;&lt;/a&gt;结构化数据：秩序与约束的领域
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;1. 核心特征&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;严格模式（Schema）：数据字段预先定义，类型明确（如整数、日期、枚举值）。&lt;/li&gt;
&lt;li&gt;二维表结构：数据以行和列的形式组织，遵循第一范式（1NF）到第三范式（3NF）的规范。&lt;/li&gt;
&lt;li&gt;强关联性：通过外键建立表间关系，支持JOIN操作实现跨表查询。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;银行账户表：&lt;code&gt;账户ID (主键) | 户主姓名 | 余额 | 开户日期&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;电商订单表：&lt;code&gt;订单ID | 用户ID (外键) | 商品ID (外键) | 订单金额 | 支付状态&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. 数据库选择&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首选：关系型数据库（RDBMS）。它的选型逻辑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事务完整性：需要ACID保障的场景（如转账操作）。&lt;/li&gt;
&lt;li&gt;复杂查询：涉及多表关联、聚合计算（如财务报表生成）。&lt;/li&gt;
&lt;li&gt;数据一致性：字段之间存在强约束（如库存数量不能为负值）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中代表方案有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MySQL/PostgreSQL：适用于中小规模OLTP系统。&lt;/li&gt;
&lt;li&gt;Oracle：企业级高并发、高可靠性需求（如金融核心系统）。&lt;/li&gt;
&lt;li&gt;TiDB：分布式架构下仍需强一致性的场景（如跨境支付平台）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 反模式案例&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;错误尝试：将用户行为日志（半结构化JSON）存入MySQL。这样做的问题是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要为动态字段创建稀疏列，导致存储空间浪费。&lt;/li&gt;
&lt;li&gt;频繁ALTER TABLE修改表结构，引发锁表风险。&lt;/li&gt;
&lt;li&gt;查询嵌套字段需解析JSON字符串，性能低下。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="半结构化数据灵活性与动态性的平衡"&gt;&lt;a href="#%e5%8d%8a%e7%bb%93%e6%9e%84%e5%8c%96%e6%95%b0%e6%8d%ae%e7%81%b5%e6%b4%bb%e6%80%a7%e4%b8%8e%e5%8a%a8%e6%80%81%e6%80%a7%e7%9a%84%e5%b9%b3%e8%a1%a1" class="header-anchor"&gt;&lt;/a&gt;半结构化数据：灵活性与动态性的平衡
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;1. 核心特征&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;松散模式：字段可动态增减，数据类型允许一定灵活性。&lt;/li&gt;
&lt;li&gt;层次化结构：数据以树形或网状形式组织（如JSON、XML）。&lt;/li&gt;
&lt;li&gt;自描述性：数据本身携带元信息（如字段名称、嵌套关系）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：用户配置文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;preferences&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;theme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;dark&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;notifications&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sms&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;last_activity&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;login&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;timestamp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2023-10-05T08:30:00Z&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;purchase&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;item_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;SKU123&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&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;p&gt;设备传感器元数据：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;device&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;D001&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;location&lt;/span&gt; &lt;span class="na"&gt;lat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;39.9042&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;lon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;116.4074&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;sensors&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;sensor&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;temperature&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;°C&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;sensor&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;humidity&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;sensors&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;device&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;2. 数据库选择&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首选技术：文档型数据库、宽列数据库。它的选型逻辑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;动态模式支持：无需预定义字段，适应业务快速迭代。&lt;/li&gt;
&lt;li&gt;嵌套查询效率：直接存储层次化数据，避免关联表拆分。&lt;/li&gt;
&lt;li&gt;局部更新能力：修改文档部分字段不影响整体结构。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代表方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;MongoDB：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;适用场景：CMS内容管理、物联网设备元数据存储。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;优势：BSON二进制存储、聚合管道、地理位置索引。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;限制：事务跨文档操作成本高（需4.0+版本）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cassandra：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;适用场景：时间序列数据（如日志事件流）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;优势：高写入吞吐、多数据中心复制。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;限制：查询必须指定分区键，二级索引效率低。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Elasticsearch：&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;适用场景：日志分析、全文检索（如电商商品搜索）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;优势：倒排索引、近实时搜索、分词器定制。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;限制：写入吞吐受分片数限制，不支持事务。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 混合架构实践&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;典型组合：MySQL + MongoDB + Elasticsearch。 数据流示例：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用户注册信息（结构化）存入MySQL。&lt;/li&gt;
&lt;li&gt;用户行为轨迹（半结构化JSON）写入MongoDB。&lt;/li&gt;
&lt;li&gt;关键字段（如用户ID、行为类型）同步到Elasticsearch供快速检索。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="非结构化数据海量与多元化的挑战"&gt;&lt;a href="#%e9%9d%9e%e7%bb%93%e6%9e%84%e5%8c%96%e6%95%b0%e6%8d%ae%e6%b5%b7%e9%87%8f%e4%b8%8e%e5%a4%9a%e5%85%83%e5%8c%96%e7%9a%84%e6%8c%91%e6%88%98" class="header-anchor"&gt;&lt;/a&gt;非结构化数据：海量与多元化的挑战
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;1. 核心特征&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无固定模式：数据格式不遵循预定义结构。&lt;/li&gt;
&lt;li&gt;大文件倾向：单个数据单元体积大（如视频、图片）。&lt;/li&gt;
&lt;li&gt;内容多样性：文本、图像、音频、二进制文件等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;媒体文件：监控摄像头的1080P视频流（MP4格式）。&lt;/li&gt;
&lt;li&gt;办公文档：PDF合同、Word报告。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. 数据库选择&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;核心矛盾：非结构化数据的管理重点不是“查询”，而是“存储与访问”。它的选型逻辑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储效率：需支持大文件分块存储（如HDFS的128MB块）。&lt;/li&gt;
&lt;li&gt;元数据管理：通过附加结构化信息实现快速检索。&lt;/li&gt;
&lt;li&gt;访问接口：提供HTTP API或对象存储接口（如S3兼容）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;代表方案：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对象存储：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Amazon S3/阿里云OSS：存储图片、视频等静态资源。&lt;/li&gt;
&lt;li&gt;MinIO：自建私有化对象存储方案。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;分布式文件系统：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;HDFS：用于Hadoop生态的原始文件存储。&lt;/li&gt;
&lt;li&gt;Ceph：统一存储池支持块、文件、对象接口。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;专用数据库扩展：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;MongoDB GridFS：将大文件分块存储为文档。&lt;/li&gt;
&lt;li&gt;PostgreSQL大对象（LOB）：通过TOAST机制存储二进制数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 元数据关联策略&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;典型架构是：对象存储 + 关系型数据库。分两步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数据流：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;上传视频文件到S3，获得存储路径&lt;code&gt;s3://bucket/video_001.mp4&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在MySQL中创建记录：&lt;/li&gt;
&lt;/ul&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="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;media_files&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s3_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uploader_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;resolution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s3://bucket/video_001.mp4&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;501&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1920x1080&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;查询过程：&lt;/li&gt;
&lt;/ol&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="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 查找用户501上传的高清视频
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&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;s3_path&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;media_files&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&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;uploader_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="mi"&gt;501&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;resolution&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;1920x1080&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="总结-1"&gt;&lt;a href="#%e6%80%bb%e7%bb%93-1" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h3&gt;&lt;p&gt;总结一下不同数据类型的特点&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/003-ff369010.png"&gt;&lt;/p&gt;
&lt;p&gt;总结来说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;结构化数据是商业规则的数字化体现，适合通过关系型数据库实现精准控制。&lt;/li&gt;
&lt;li&gt;半结构化数据反映了现实世界的复杂关联，文档型或宽列数据库提供必要的灵活性。&lt;/li&gt;
&lt;li&gt;非结构化数据代表信息的原始形态，需通过对象存储与元数据管理实现规模化处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;说了这么多，虽然对于数据是什么类型有了比较清楚的定义和区分，但是数据到底是结构化的还是非结构化的，其实&lt;strong&gt;主要是看 “数据的组织方式”和“处理方式”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这里举个例子，比如 &lt;code&gt;用户评论&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;如果我们只是想简单的读写用户评论，可以把它用关系型数据库存储，当作一个表中的一个字段:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;在评论内容（CommentContent）这个字段中，我们可以存储用户的评论文本。对于包含的表情、图片等多媒体元素，也有一些常见的处理方法。例如，把表情转换为编码存储，而图片可以存储在文件服务器上，并在数据库中保存链接地址。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;如果把用户评论当成非结构化数据，那么它的&lt;strong&gt;处理方式&lt;/strong&gt;就会更加复杂。&lt;/p&gt;
&lt;p&gt;用户评论的内容通常是文本信息，但其实不容易进行有效的结构化处理。评论的长度、格式、语言等都可能差异很大，甚至某些评论可能包含表情符号或者图片等多媒体元素。这些元素都无法通过预定义的数据模型进行有效地分类和组织，因此我们将其当做非结构化数据来处理。&amp;ndash;这里主要是指数据的&lt;strong&gt;组织方式&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;以下是一些具体的例子：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;评论情感分析：通过对用户评论的文本内容分析，我们可以识别出评论者的情绪态度，比如正面的、负面的，或者中性的。这对于公司来说是非常重要的，可以了解产品或者服务在消费者中的口碑和接受程度。&lt;/li&gt;
&lt;li&gt;评论分类：我们还可以将评论分到不同的类别。可以根据情绪分为好评、中评、差评。同时，还可以按照评论的内容将其分为产品评价，客服评价等类别。&lt;/li&gt;
&lt;li&gt;评论的全文搜索：对于用户评论这种非结构化数据的全文搜索，可以帮助我们即时搜索到关于某一产品或者某一特定主题的所有相关评论。&lt;/li&gt;
&lt;li&gt;主题模型：主题模型可以帮助我们从大量的评论中提炼出几个主要的话题，帮助公司了解消费者最关心的问题有哪些。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;具体实现架构如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/004-560fe49f.png"&gt;&lt;/p&gt;
&lt;p&gt;用户评论的存储与分析系统需结合多种技术实现高效处理。在存储层设计中，推荐采用混合存储架构以满足非结构化数据的持久化需求。核心存储使用MongoDB文档数据库保存完整的评论内容（如文本、表情编码、图片链接等），其灵活的JSON结构支持动态字段扩展，例如可包含用户设备信息、地理位置等元数据。同时，MongoDB的水平扩展能力和聚合查询功能可有效支持大规模数据管理。对于评论中的图片、视频等二进制文件，则通过对象存储（如Amazon S3或阿里云OSS）存储，结合预签名URL实现安全访问，避免数据库性能损耗。辅助索引层采用Elasticsearch同步关键字段，通过倒排索引和中文分词技术（如IK分词）实现秒级全文检索，并支持模糊搜索与高亮显示。&lt;/p&gt;
&lt;p&gt;在场景化应用中，情感分析可通过多种技术实现：对于中文评论，SnowNLP或Hugging Face的BERT模型能精准识别情感倾向，例如通过预训练模型对“电池续航太差”等文本输出负面标签及置信度评分。评论分类则结合监督学习（如SVM、BERT）与无监督方法（如K-Means聚类），通过FastAPI构建实时分类服务或使用Spark进行批量处理。全文搜索功能由Elasticsearch支撑，通过MongoDB Connector实现实时数据同步，支持用户快速定位包含特定关键词的评论内容。主题模型则利用LDA、BERTopic等算法从海量评论中提取高频主题（如“屏幕质量”“物流服务”），并通过WordCloud等工具可视化呈现，帮助业务方洞察用户关注焦点。整个架构通过混合存储与多技术协同，在保证性能的同时实现成本优化。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="应用场景"&gt;&lt;a href="#%e5%ba%94%e7%94%a8%e5%9c%ba%e6%99%af" class="header-anchor"&gt;&lt;/a&gt;应用场景
&lt;/h2&gt;&lt;p&gt;数据库选型的核心是：理解业务数据的生命周期，把握各类数据库的能力边界，在架构灵活性与技术可控性之间寻找最佳平衡点。任何脱离具体业务场景的数据库对比都是无效的，优秀的架构设计应当像精密钟表般，让每个齿轮（数据库）在最适合的位置发挥最大效能。&lt;/p&gt;
&lt;p&gt;结合典型应用场景，什么场景应该用什么数据库呢？其实在一个业务场景下需要多种类数据库结合使用，总结如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/005-00b9fa8f.png"&gt;&lt;/p&gt;
&lt;p&gt;我们以单个数据库为维度再分别讨论一下：&lt;/p&gt;
&lt;h3 id="关系型mysql"&gt;&lt;a href="#%e5%85%b3%e7%b3%bb%e5%9e%8bmysql" class="header-anchor"&gt;&lt;/a&gt;关系型:MySQL
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/006-22a3aff1.png"&gt;&lt;/p&gt;
&lt;p&gt;MySQL：高并发事务系统（如电商订单处理）&lt;/p&gt;
&lt;p&gt;核心场景：电商平台的订单系统，需要保证每笔交易的原子性（如扣减库存、生成订单、支付记录必须同时成功或回滚）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择MySQL&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ACID事务支持：通过InnoDB引擎实现强一致性，确保订单状态的准确性。&lt;/li&gt;
&lt;li&gt;复杂查询能力：支持多表JOIN（如查询用户历史订单及商品详情）。&lt;/li&gt;
&lt;li&gt;成熟生态：主从复制、分库分表工具（如ShardingSphere）支持高可用和扩展。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;：不支持跨文档事务（早期版本），不适合强一致性场景。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis&lt;/strong&gt;：内存数据库，无法持久化复杂事务逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：每秒处理10万笔订单的电商平台，通过MySQL分库分表（按用户ID哈希）实现横向扩展。&lt;/p&gt;
&lt;h3 id="搜索引擎es"&gt;&lt;a href="#%e6%90%9c%e7%b4%a2%e5%bc%95%e6%93%8ees" class="header-anchor"&gt;&lt;/a&gt;搜索引擎：ES
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/007-559c2219.png"&gt;&lt;/p&gt;
&lt;p&gt;Elasticsearch：实时商品搜索与日志分析&lt;/p&gt;
&lt;p&gt;核心场景：电商平台商品搜索，用户输入关键词（如“防水运动鞋”）后毫秒级返回结果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择Elasticsearch&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;倒排索引&lt;/strong&gt;：快速匹配关键词，支持分词、同义词扩展、模糊查询。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;聚合分析&lt;/strong&gt;：统计商品类目的平均评分、价格区间分布。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;近实时（NRT）&lt;/strong&gt;：新上架商品1秒内可被搜索。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：全文索引性能差，无法支持高并发搜索。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;：文本搜索功能简单，缺乏分词器和相关性排序。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：某跨境电商平台，每日处理1亿次搜索请求，通过ES集群（分片+副本）实现99.9%的查询响应时间&amp;lt;50ms。&lt;/p&gt;
&lt;h3 id="文档型mongodb"&gt;&lt;a href="#%e6%96%87%e6%a1%a3%e5%9e%8bmongodb" class="header-anchor"&gt;&lt;/a&gt;文档型：MongoDB
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/008-6afc9d95.png"&gt;&lt;/p&gt;
&lt;p&gt;MongoDB：内容管理系统（CMS）与动态配置存储**&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心场景&lt;/strong&gt;：新闻发布平台的文章存储，每篇文章包含标题、正文、多级评论、动态标签。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择MongoDB&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;灵活文档模型&lt;/strong&gt;：存储嵌套结构的JSON数据（如评论树形结构）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;水平扩展&lt;/strong&gt;：通过Sharding自动分配数据到多个分片。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;局部更新&lt;/strong&gt;：修改文章某个字段无需重写整个文档。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：需要拆分为多张表（文章表、评论表），JOIN查询效率低。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HBase&lt;/strong&gt;：适合结构化扫描，不适合嵌套数据查询。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：某媒体平台存储1000万篇文章，每篇文章包含动态标签（如“科技, 2023趋势”），通过MongoDB的文档结构直接存储。&lt;/p&gt;
&lt;h3 id="键值存储redis"&gt;&lt;a href="#%e9%94%ae%e5%80%bc%e5%ad%98%e5%82%a8redis" class="header-anchor"&gt;&lt;/a&gt;键值存储：Redis
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/009-116b15b9.png"&gt;&lt;/p&gt;
&lt;p&gt;Redis：高频访问缓存与会话管理&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心场景&lt;/strong&gt;：社交平台的热门帖子缓存，用户访问时优先从缓存读取，减少数据库压力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择Redis&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内存存储&lt;/strong&gt;：读写延迟&amp;lt;1ms，支持每秒百万级操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据结构丰富&lt;/strong&gt;：使用Sorted Set存储热门帖子排行榜，Hash存储用户会话信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持久化可选&lt;/strong&gt;：RDB快照或AOF日志保障数据安全。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：磁盘存储，无法满足毫秒级响应。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;：内存占用高，不适合纯缓存场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：某论坛每日活跃用户500万，通过Redis缓存前1000热门帖子，命中率90%，数据库负载下降70%。&lt;/p&gt;
&lt;h3 id="宽列存储hbasecassandra"&gt;&lt;a href="#%e5%ae%bd%e5%88%97%e5%ad%98%e5%82%a8hbasecassandra" class="header-anchor"&gt;&lt;/a&gt;宽列存储：HBase、Cassandra
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/010-9e144a87.png"&gt;&lt;/p&gt;
&lt;p&gt;HBase：海量时序数据存储（如物联网设备监控）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心场景&lt;/strong&gt;：电力公司存储智能电表每秒采集的电流、电压数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择HBase&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;列族存储&lt;/strong&gt;：按列压缩时序数据，节省存储空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;随机读写&lt;/strong&gt;：按设备ID+时间戳快速查询某时刻数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HDFS集成&lt;/strong&gt;：数据自动下沉至HDFS实现低成本归档。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cassandra&lt;/strong&gt;：适合跨数据中心写入，但单点查询性能不如HBase。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：无法支持每秒百万级数据写入。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：某物联网平台每日新增1TB传感器数据，通过HBase的RowKey设计（设备ID+时间戳）实现毫秒级查询。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/011-87d2288b.png"&gt;&lt;/p&gt;
&lt;p&gt;Cassandra：多数据中心日志同步（如全球化应用）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心场景&lt;/strong&gt;：跨国社交应用的聊天日志存储，要求数据在欧美亚三地就近写入且最终一致。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择Cassandra&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;多活架构&lt;/strong&gt;：数据自动复制到多个数据中心，写入本地即成功。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高吞吐写入&lt;/strong&gt;：LSM树引擎支持每秒百万级写入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无单点故障&lt;/strong&gt;：去中心化架构避免主从瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HBase&lt;/strong&gt;：依赖HDFS和ZooKeeper，扩展性受限。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：主从复制跨地域延迟高。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：某IM应用每日处理50亿条消息，通过Cassandra实现三地数据中心写入延迟&amp;lt;10ms。&lt;/p&gt;
&lt;h3 id="数据仓库hive"&gt;&lt;a href="#%e6%95%b0%e6%8d%ae%e4%bb%93%e5%ba%93hive" class="header-anchor"&gt;&lt;/a&gt;数据仓库：Hive
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/012-a845c0c5.png"&gt;&lt;/p&gt;
&lt;p&gt;Hive：离线数据仓库与ETL批处理&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心场景&lt;/strong&gt;：零售企业每月销售数据的批量清洗与报表生成。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择Hive&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQL兼容&lt;/strong&gt;：通过HiveQL实现类SQL查询，降低学习成本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;海量数据批处理&lt;/strong&gt;：基于MapReduce或Tez引擎处理TB级数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;低成本存储&lt;/strong&gt;：数据存储在HDFS，支持压缩格式（ORC、Parquet）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ClickHouse&lt;/strong&gt;：适合实时分析，但存储成本高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：无法处理PB级数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：某电商每月分析10TB历史订单数据，通过Hive生成“年度区域销售趋势”报表，耗时2小时。&lt;/p&gt;
&lt;h3 id="列式存储clickhouse"&gt;&lt;a href="#%e5%88%97%e5%bc%8f%e5%ad%98%e5%82%a8clickhouse" class="header-anchor"&gt;&lt;/a&gt;列式存储：ClickHouse
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/013-c7953de3.png"&gt;&lt;/p&gt;
&lt;p&gt;ClickHouse：实时OLAP与用户行为分析&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心场景&lt;/strong&gt;：广告平台的实时点击流分析，每日处理千亿级事件，生成实时报表。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择ClickHouse&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;列式存储&lt;/strong&gt;：压缩率高，适合聚合计算（如SUM、COUNT）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;向量化执行&lt;/strong&gt;：利用CPU SIMD指令加速查询。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时写入&lt;/strong&gt;：支持Kafka直接导入数据，延迟低至秒级。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hive&lt;/strong&gt;：批处理模式，查询延迟分钟级。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：无法支撑海量数据聚合。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：某广告平台分析每日200亿次点击事件，通过ClickHouse集群实现“过去1小时各渠道转化率”秒级响应。&lt;/p&gt;
&lt;h3 id="图数据库neo4j"&gt;&lt;a href="#%e5%9b%be%e6%95%b0%e6%8d%ae%e5%ba%93neo4j" class="header-anchor"&gt;&lt;/a&gt;图数据库：Neo4j
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/014-d3af3ea6.png"&gt;&lt;/p&gt;
&lt;p&gt;Neo4j：社交网络关系挖掘（如好友推荐）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心场景&lt;/strong&gt;：社交平台的“六度关系”分析，计算用户A到用户B的最短路径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么选择Neo4j&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;图遍历优化&lt;/strong&gt;：通过原生图存储引擎高效遍历多跳关系。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cypher查询语言&lt;/strong&gt;：直观表达复杂关系模式（如查找共同好友）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时更新&lt;/strong&gt;：支持动态添加节点和边。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;对比其他数据库&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MySQL&lt;/strong&gt;：需递归JOIN，性能随跳数指数级下降。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;：无法直接表达关系网络。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;：某社交平台分析10亿用户关系，Neo4j可在毫秒级返回“用户A的三度人脉中可能认识的人”。&lt;/p&gt;
&lt;h3 id="总结-2"&gt;&lt;a href="#%e6%80%bb%e7%bb%93-2" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;事务强一致&lt;/strong&gt; → MySQL&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时搜索&lt;/strong&gt; → Elasticsearch&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态文档&lt;/strong&gt; → MongoDB&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高频缓存&lt;/strong&gt; → Redis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实时OLAP&lt;/strong&gt; → ClickHouse&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时序海量存储&lt;/strong&gt; → HBase&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全球化写入&lt;/strong&gt; → Cassandra&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关系网络&lt;/strong&gt; → Neo4j&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;离线批处理&lt;/strong&gt; → Hive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/015-95068fb0.png"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="最后总结"&gt;&lt;a href="#%e6%9c%80%e5%90%8e%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;最后总结
&lt;/h2&gt;&lt;p&gt;**数据模型的本质差异是选型的第一道分水岭。**关系型数据库（如MySQL、PostgreSQL）建立在严格的二维表结构之上，通过外键约束和范式理论保障数据完整性。这种结构特别适合需要复杂关联查询的财务系统、ERP等业务场景。例如银行转账操作需要严格遵循ACID事务原则，MySQL的InnoDB引擎通过行级锁和MVCC机制实现事务隔离，配合主从复制架构可以满足多数金融级需求。但在物联网设备日志存储场景下，每天千万级的写入请求会导致关系型数据库的索引维护成本急剧上升，此时文档型数据库MongoDB的BSON自由格式和分片集群优势便显现出来。MongoDB的写操作默认不等待磁盘确认，通过内存映射文件实现高速写入，特别适合内容管理系统或实时分析场景中半结构化数据的快速摄入。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分布式架构的CAP权衡直接影响系统可用性。&lt;/strong&gt; Elasticsearch作为分布式搜索引擎，其倒排索引结构对文本检索的优化已达到毫秒级响应，在电商商品搜索、日志分析等场景具有不可替代性。但ES的强一致性模型可能导致集群脑裂风险，需要结合zen discovery机制进行节点状态管理。相比之下，HBase作为Hadoop生态的列式存储，通过RegionServer的水平扩展和LSM树的写入优化，能够承载PB级数据量的实时读写。某智慧城市项目曾使用HBase存储数十亿条交通卡口数据，利用其行键有序分布特性实现车辆轨迹的快速回溯，这是传统关系型数据库难以企及的吞吐能力。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;计算与存储的分离趋势重构了数据分析范式。&lt;/strong&gt; Hive建立在HDFS之上的元数据管理机制，通过类SQL语法实现大数据集的离线分析，其分区表和桶表的设计显著提升了TB级数据查询效率。某电商平台的历史订单分析采用Hive进行月度销售统计，配合Tez执行引擎将任务耗时从小时级压缩到分钟级。但Hive的高延迟特性使其不适合实时查询场景，这正是ClickHouse等OLAP数据库的突破方向。需要特别注意的是，数据湖架构的兴起使得Delta Lake、Hudi等解决方案开始融合事务管理和批流一体处理，这对传统数仓选型提出了新的挑战。&lt;/p&gt;
&lt;p&gt;**事务完整性与系统弹性的平衡艺术。**当业务需要跨数据库操作时，如电商订单系统同时涉及MySQL库存扣减和MongoDB订单日志记录，分布式事务管理就成为关键挑战。Saga模式通过补偿机制实现最终一致性，而Seata框架的AT模式能在业务侵入性较低的情况下保障事务边界。但在高并发场景下，这类方案的性能损耗可能达到20%-30%，这就需要架构师在一致性级别和系统吞吐之间做出权衡。例如社交平台的点赞功能更适合使用Redis的原子计数器，完全放弃强一致性以换取百万级QPS的处理能力。&lt;/p&gt;
&lt;p&gt;**硬件成本与运维复杂度的隐藏成本。**云原生时代，AWS Aurora通过计算存储分离架构实现了MySQL兼容数据库的自动扩缩容，其存储层可自动扩展到128TB，这种托管服务显著降低了运维负担。但对于需要定制化优化的场景，如金融行业的风控模型计算，仍需要基于物理机部署的Oracle RAC集群来保障IOPS性能。开源方案的隐性成本同样不容忽视，Elasticsearch集群的JVM堆内存配置直接影响索引性能，不当的分片设置可能导致磁盘空间浪费，这需要运维团队积累足够的调优经验。&lt;/p&gt;
&lt;p&gt;在具体选型实践中，建议采用四维评估法：首先明确数据结构化程度（结构化、半结构化、非结构化），其次分析读写比例和并发量级，再次确定一致性要求（强一致、最终一致），最后考量扩展性和生态集成需求。例如智能穿戴设备数据采集场景，设备标识符作为MongoDB文档的天然主键，时间序列数据采用嵌套文档存储，既避免了关系型数据库的表关联开销，又利用TTL索引实现自动过期清理。而在用户画像分析场景，HBase 的宽表结构可以存储数千个用户标签，配合Phoenix的SQL层实现灵活查询，这种架构组合充分发挥了列式存储的高压缩比优势。&lt;/p&gt;
&lt;p&gt;最后我们用一个简单的流程图来说明一下这个选型过程：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-03-14-shu-ju-ku-xuan-xing-zhong-ji-zhi-nan-cong-shu-ju-lei-xing-da/016-d55b1bf4.png"&gt;&lt;/p&gt;</description></item><item><title>Milvus实战：如何用一个数据库提升你的AI项目性能</title><link>https://xiaobox.github.io/p/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/</link><pubDate>Fri, 11 Oct 2024 08:22:08 +0000</pubDate><guid>https://xiaobox.github.io/p/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/cover.jpg" alt="Featured image of post Milvus实战：如何用一个数据库提升你的AI项目性能" /&gt;&lt;h2 id="回顾"&gt;&lt;a href="#%e5%9b%9e%e9%a1%be" class="header-anchor"&gt;&lt;/a&gt;回顾
&lt;/h2&gt;&lt;p&gt;在上一文中我们使用 LlamaIndex 整合 智谱 AI 的 GLM-4 和 Embedding-3 模型一起构建 RAG 应用。&lt;/p&gt;
&lt;p&gt;在上篇文章的最后，我们发现因为 Embedding-3 模型是同步调用的，所以从测试效果看比较慢。每一次运行都产生了大量的 http 同步请求。文末我说解决的办法可以在本地部署一个开源的 embedding 模型，这样就不会产生远程的 http 调用了，而且也比较省钱。&lt;/p&gt;
&lt;p&gt;这是个办法，但实际上还有其他的好办法。&lt;/p&gt;
&lt;p&gt;我们可以将 &lt;strong&gt;文档通过 embedding 模型产生的向量存储起来，这样相同的文档，只有在第一次 embedding 时会慢一些，再次检索时，可以快速地将已经保存好的向量查询出来使用。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="本地文件存储"&gt;&lt;a href="#%e6%9c%ac%e5%9c%b0%e6%96%87%e4%bb%b6%e5%ad%98%e5%82%a8" class="header-anchor"&gt;&lt;/a&gt;本地文件存储
&lt;/h2&gt;&lt;p&gt;利用 LlamaIndex 的 API ，我们可以非常方便地把向量存储到本地文件，以下是一个例子，我把向量存储到项目的 &lt;code&gt;index&lt;/code&gt;目录下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_or_create_index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 检查是否存在有效的持久化索引&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;.json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;正在加载现有索引。..&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;storage_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StorageContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_defaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persist_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;load_index_from_storage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;storage_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;未找到有效的现有索引，正在创建新索引。..&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 使用预定义的 DATA_DIR 常量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./data&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 创建新索引，显示 embedding 进度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorStoreIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;show_progress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 持久化索引&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;19&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage_context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persist_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;20&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;索引已创建并保存到本地。&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;21&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;22&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;看起来代码多，实际上重要的就是这两行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;storage_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StorageContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_defaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;persist_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;index&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;load_index_from_storage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;storage_context&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;p&gt;也很容易理解，见文知意。&lt;/p&gt;
&lt;p&gt;索引创建后，&lt;code&gt;index&lt;/code&gt; 会自动创建一些文件来保存向量信息：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/001-33676f25.png"&gt;&lt;/p&gt;
&lt;h2 id="向量数据库"&gt;&lt;a href="#%e5%90%91%e9%87%8f%e6%95%b0%e6%8d%ae%e5%ba%93" class="header-anchor"&gt;&lt;/a&gt;向量数据库
&lt;/h2&gt;&lt;p&gt;一般情况下，比如小型项目，将向量数据保存在系统文件中就已经够用了。但是，在中大型项目中，由于数据规模较大，使用人数较多，为了方便管理和扩展，我们会使用专业的向量数据库来存储和管理向量数据。&lt;/p&gt;
&lt;p&gt;你可以借助下图了解下向量数据库在 AIGC 应用架构中的位置和作用&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/002-4d7dc065.png"&gt;&lt;/p&gt;
&lt;h3 id="向量数据库选型"&gt;&lt;a href="#%e5%90%91%e9%87%8f%e6%95%b0%e6%8d%ae%e5%ba%93%e9%80%89%e5%9e%8b" class="header-anchor"&gt;&lt;/a&gt;向量数据库选型
&lt;/h3&gt;
 &lt;blockquote&gt;
 &lt;p&gt;“&lt;/p&gt;
&lt;p&gt;RAG 系统的成功在很大程度上取决于其高效地获取和处理海量信息的能力。向量数据库又在其中发挥了不可替代的作用，并构成了 RAG 系统的核心&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;不看不知道，作为一个数据库软件 ，目前向量数据库领域是真卷啊，打眼一看至少有几十个。知名的也得有 10 几个。&lt;/p&gt;
&lt;p&gt;说实话，最开始还真有些茫然，有点儿挑花眼了，我们这里列举几个知名的向量数据库：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Milvus&lt;/strong&gt; 是一个 2019 年开源的纯向量数据库，号称全球最先进的开源向量数据库。它是 &lt;code&gt;LF AI &amp;amp; Data Foundation&lt;/code&gt;（简称 &lt;strong&gt;LFAI，它相当于 CNCF 在云原生界的地位&lt;/strong&gt;）赞助的毕业项目&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Chroma&lt;/strong&gt; 是一个相对较新的向量数据库，目前它的设计确实是以单节点模式为主，主要用于中小型应用或开发测试环境。然而，对于需要更高可用性和横向扩展能力的生产环境，Chroma 当前的版本可能还不完全满足需求。Chroma 内置了 &lt;code&gt;SQLite&lt;/code&gt; 作为其底层存储引擎&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Weaviate&lt;/strong&gt; ：是一个云原生的、开源的向量数据库。专为大规模的向量数据存储和检索设计。它结合了向量搜索和图数据库的优势，适用于机器学习、推荐系统、图像识别和自然语言处理等场景。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Faiss&lt;/strong&gt; ：由 Facebook AI Research 开发的 Faiss 是一个开源库，用于快速、密集向量相似性搜索和分组&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Qdrant&lt;/strong&gt; 是一个开源的向量数据库，专为高效的大规模向量数据存储和检索设计。它适用于机器学习、推荐系统、图像识别和自然语言处理等场景，提供了高性能和易用性的结合。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PGVector&lt;/strong&gt; 是一个基于 PostgreSQL 的扩展插件，旨在提供强大的向量存储和查询功能，PGVector 可以无缝集成到现有的 PostgreSQL 数据库中，用户无需迁移现有的数据库即可开始使用向量搜索功能。因为是 PostgreSQL 插件，借助 PostgreSQL 的长期开发和优化，PGVector 继承了其可靠性和稳健性，同时在向量化处理方面进行了增强。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整体上看在向量数据库领域有这么几类玩家：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;专做向量数据库的，大部分是开源的，如 Chroma、Weaviate 等&lt;/li&gt;
&lt;li&gt;做关系型数据库的扩展或插件，如 PGVector&lt;/li&gt;
&lt;li&gt;做 NoSQL 数据库的功能扩展或兼容，如 &lt;code&gt;Elasticsearch&lt;/code&gt;、 &lt;code&gt;Redis&lt;/code&gt;、 &lt;code&gt;ClickHouse&lt;/code&gt; 等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;太多了，真是太多了，最开始我做选型的时候真是有点儿挑花眼了。最后，一点点缩小范围，最终进入决赛圈的是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Qdrant&lt;/li&gt;
&lt;li&gt;Weaviate&lt;/li&gt;
&lt;li&gt;Milvus&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;你可以通过 &lt;a class="link" href="https://zilliz.com.cn/comparison" target="_blank" rel="noopener"
 &gt;https://zilliz.com.cn/comparison&lt;/a&gt; 来了解各向量数据库之间的对比情况&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/003-5681900f.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/004-331f1c43.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;最终我选择了 Milvus&lt;/strong&gt; 原因是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它确实很知名，看了那么多评测，各方面性能都很能打&lt;/li&gt;
&lt;li&gt;我个人觉得比较重要的是它还有数据库管理客户端 &lt;code&gt;attu&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;向量数据库不像我之前使用过的关系型数据库，一般是没有像 &lt;code&gt;Navicat&lt;/code&gt; 、&lt;code&gt;DataGrip&lt;/code&gt; 这样的数据库管理客户端的。一般只有 CRUD 接口或 CLI 客户端。这对于初学者了解和学习向量数据库不太友好，所以我还是特别希望有这样一个有 GUI 图形界面、看得见摸得着的客户端的，而 Milvus 正好是有的。就是 &lt;code&gt;attu&lt;/code&gt; （可以通过 &lt;a class="link" href="https://github.com/zilliztech/attu" target="_blank" rel="noopener"
 &gt;https://github.com/zilliztech/attu&lt;/a&gt; 下载）&lt;/p&gt;
&lt;p&gt;如果你也和我一样在 Qdrant、Weaviate、Milvus 之间纠结的话，可以参考网上一位大哥对它们的评价：&lt;strong&gt;“总结起来就是，Qdrant 开销特别小，Weaviate 支持向量搜索、对象存储和倒排索引的组合，Milvus 性能最强、花活最多。”&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="chroma"&gt;&lt;a href="#chroma" class="header-anchor"&gt;&lt;/a&gt;Chroma
&lt;/h2&gt;&lt;p&gt;LlamaIndex 官方的例子使用的是 Chroma 作为向量数据库进行向量存储。&lt;/p&gt;
&lt;p&gt;默认情况下，Chroma 会将向量数据存储在本地文件系统中。我们就以 Chroma 为例写个例子。&lt;/p&gt;
&lt;p&gt;Chroma 不需要安装外部软件，安装导入相关的库就可了&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;import chromadb
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;from llama_index.vector_stores.chroma import ChromaVectorStore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在导入了 Chroma 相关的库后，我们将 &lt;code&gt;load_or_create_index()&lt;/code&gt; 方法调整一下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_or_create_index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 初始化客户端，设置数据保存路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chromadb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PersistentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./chroma_db&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 创建或获取集合&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;chroma_collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_or_create_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;quickstart&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 将 chroma 指定为上下文的 vector_store&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vector_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChromaVectorStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chroma_collection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;chroma_collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;storage_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StorageContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_defaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 检查集合是否为空&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;chroma_collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 如果集合为空，加载文档并创建新的索引&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./data&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorStoreIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;storage_context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;storage_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;已创建新的索引&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 如果集合不为空，直接从 vector_store 加载索引&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;19&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorStoreIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_vector_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;storage_context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;storage_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;20&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;已加载现有索引&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;21&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;22&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到也很简单。程序运行后，&lt;code&gt;chroma_db&lt;/code&gt; 文件夹下会自动创建以下文件：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/005-79a82529.png"&gt;&lt;/p&gt;
&lt;p&gt;前文中我们提到过 chroma 内置了 &lt;code&gt;SQLite&lt;/code&gt; ，这里就体现出来了。&lt;/p&gt;
&lt;h2 id="milvus"&gt;&lt;a href="#milvus" class="header-anchor"&gt;&lt;/a&gt;Milvus
&lt;/h2&gt;&lt;p&gt;在使用 Milvus 前我们需要先安装它。它有多种安装方式，我本地通过 Docker-Compose 安装&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3.5&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;etcd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;milvus-etcd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;quay.io/coreos/etcd:v3.5.14&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;ETCD_AUTO_COMPACTION_MODE=revision&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;ETCD_AUTO_COMPACTION_RETENTION=1000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;ETCD_QUOTA_BACKEND_BYTES=4294967296&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;ETCD_SNAPSHOT_COUNT=50000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;etcdctl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;endpoint&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;health&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;30s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;20s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;19&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;20&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;21&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;minio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;22&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;milvus-minio&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;23&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;minio/minio:RELEASE.2023-03-20T20-16-18Z&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;24&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;25&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MINIO_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;minioadmin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;26&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MINIO_SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;minioadmin&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;27&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;28&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;9001:9001&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;29&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;9000:9000&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;30&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;31&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;32&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;minio server /minio_data --console-address &amp;#34;:9001&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;33&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;34&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;curl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-f&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://localhost:9000/minio/health/live&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;35&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;30s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;36&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;20s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;37&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;38&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;39&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;40&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;milvus-standalone&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;41&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;milvusdb/milvus:v2.3.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;42&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;milvus&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;run&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;standalone&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;43&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;security_opt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;44&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;seccomp:unconfined&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;45&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;46&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MINIO_REGION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-east-1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;47&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ETCD_ENDPOINTS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;etcd:2379&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;48&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MINIO_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;minio:9000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;49&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;50&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;51&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;healthcheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;52&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;curl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;-f&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://localhost:9091/healthz&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;53&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;30s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;54&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;start_period&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;90s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;55&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;20s&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;56&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;57&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;58&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;19530:19530&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;59&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;9091:9091&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;60&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;61&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;etcd&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;62&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;minio&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;63&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;64&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;networks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;65&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;66&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;milvus&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装好以后，可以看到它内部有三个容器：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/006-b694b4d5.png"&gt;&lt;/p&gt;
&lt;p&gt;接着我们安装 attu，它的安装比较简单，下载相关平台的安装文件安装即可&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/007-4bc242b7.png"&gt;&lt;/p&gt;
&lt;p&gt;attu 安装完成后打开进行 Milvus 的连接：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/008-1963366f.png"&gt;&lt;/p&gt;
&lt;p&gt;默认地址是 &lt;code&gt;127.0.0.1:19530&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;接着，我们来到程序这里，进行连接和使用，同样，要先导入库&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;from llama_index.vector_stores.milvus import MilvusVectorStore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后我们调整一下之前的方法，改写一个新的方法来连接 Miluvs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_or_create_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 获取或创建索引
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; overwrite 设置为 False 意味着如果同名的集合已存在，将不会覆盖它。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; dim 是向量维度，必须与 embedding 模型的维度一致。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vector_store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MilvusVectorStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://localhost:19530&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;overwrite&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;collection_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;llamaindex_collection&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;storage_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StorageContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_defaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./data&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorStoreIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;storage_context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;storage_context&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;19&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;20&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;已成功创建并存储新的索引。&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;21&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;22&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorStoreIndex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_vector_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vector_store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;23&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;24&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我相信如果你阅读了前文，知道这段代码的重要点在哪里。&lt;/p&gt;
&lt;p&gt;当 RAG 应用程序正常运行后，向量数据就被存储到了 Milvus 数据库中：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/009-ef9054d1.png"&gt;&lt;/p&gt;
&lt;p&gt;有了 GUI 界面，就比较直观地能感受到向量数据是个什么样子了。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/010-fbd533b2.png"&gt;&lt;/p&gt;
&lt;p&gt;有关在 attu 中进行向量数据的查询等操作可以参数相关文档，本文就不多说了。&lt;/p&gt;
&lt;p&gt;使用向量数据库存储以后，我们再次运行查询，速度就很快了，因为第一次运行的时候就已经把文档 embedding 后的向量存储起来了，只需要从 Milvus 中加载查询就可以了，不用再走 http 远程调用。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-10-11-milvus-shi-zhan-ru-he-yong-yi-ge-shu-ju-ku-ti-sheng-ni-de-ai/011-14a85a67.png"&gt;&lt;/p&gt;
&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h2&gt;&lt;p&gt;在本文中，我们深入探讨了如何通过 LlamaIndex 整合智谱 AI 的 GLM-4 和 Embedding-3 模型来构建 RAG 应用，并针对 Embedding-3 模型同步调用导致的性能瓶颈问题，提出了有效的解决方案。我们发现，将文档的向量存储起来，可以显著提高检索速度，避免了重复的 HTTP 同步请求，从而节省了成本和时间。&lt;/p&gt;
&lt;p&gt;通过本地文件存储和向量数据库的选型，我们对比了多种向量数据库的特点和性能，最终选择了 Milvus 作为我们的向量数据库。Milvus 以其卓越的性能和易用性脱颖而出，特别是其数据库管理客户端 attu，为初学者提供了友好的图形界面，使得向量数据库的管理和操作变得更加直观和便捷。&lt;/p&gt;
&lt;p&gt;在实际应用中，我们通过 Docker-Compose 安装了 Milvus，并利用 attu 进行了连接和操作。通过将向量数据存储到 Milvus 数据库中，我们显著提高了查询速度，因为文档的向量在第一次运行时就已经被存储起来，后续的查询可以直接从 Milvus 中加载，无需再次进行远程 HTTP 调用。&lt;/p&gt;
&lt;p&gt;此外，我们还探讨了使用 Chroma 作为向量数据库的方案，它内置了 SQLite，简化了安装和使用过程。通过 LlamaIndex 的 API，我们可以轻松地将向量存储到本地文件或 Chroma 数据库中，进一步增强了 RAG 应用的性能和可扩展性。&lt;/p&gt;
&lt;p&gt;总的来说，通过本文的探讨和实践，我们不仅解决了 RAG 应用中的性能问题，还为中大型项目提供了一种高效、可扩展的向量数据存储和管理方案。随着 AI 技术的不断发展，向量数据库在 AIGC 应用架构中的作用将越来越重要，而 Milvus 等向量数据库的选择和应用，将为构建更加智能和高效的 AI 应用提供强有力的支持。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;本文所涉及的完整代码在该项目中：https://github.com/xiaobox/llamaindex_test 大家可按需自取&lt;/em&gt;&lt;/p&gt;</description></item><item><title>数据库选型必看：MySQL 与 MariaDB 功能对比全解析</title><link>https://xiaobox.github.io/p/2024-09-09-shu-ju-ku-xuan-xing-bi-kan-mysql-yu-mariadb-gong-neng-dui-bi/</link><pubDate>Mon, 09 Sep 2024 04:12:18 +0000</pubDate><guid>https://xiaobox.github.io/p/2024-09-09-shu-ju-ku-xuan-xing-bi-kan-mysql-yu-mariadb-gong-neng-dui-bi/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-09-09-shu-ju-ku-xuan-xing-bi-kan-mysql-yu-mariadb-gong-neng-dui-bi/cover.jpg" alt="Featured image of post 数据库选型必看：MySQL 与 MariaDB 功能对比全解析" /&gt;&lt;h2 id="引言"&gt;&lt;a href="#%e5%bc%95%e8%a8%80" class="header-anchor"&gt;&lt;/a&gt;引言
&lt;/h2&gt;&lt;p&gt;在当今的数据驱动世界中，数据库的选择对任何企业和开发者来说都是一个至关重要的决策。MySQL 和 MariaDB，这两款数据库管理系统（DBMS）因其高性能、稳定性和广泛的应用场景而广受欢迎。尽管它们有着共同的起源，但随着时间的推移，两者在功能特性和发展路线上逐渐展现出差异。本文将深入探讨 MySQL 与 MariaDB 在表格定义和数据定义语言（DDL）方面的不同，并针对模式变更操作提供实用的指南。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-09-09-shu-ju-ku-xuan-xing-bi-kan-mysql-yu-mariadb-gong-neng-dui-bi/001-edac8409.png"&gt;&lt;/p&gt;
&lt;h2 id="一表格功能差异详解"&gt;&lt;a href="#%e4%b8%80%e8%a1%a8%e6%a0%bc%e5%8a%9f%e8%83%bd%e5%b7%ae%e5%bc%82%e8%af%a6%e8%a7%a3" class="header-anchor"&gt;&lt;/a&gt;一、表格功能差异详解
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;JSON 列类型&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MySQL 的 JSON 支持&lt;/strong&gt;：MySQL 从 5.7 版本开始引入了原生的 JSON 数据类型，这使得存储和查询 JSON 文档变得更加高效。这一特性对于需要处理复杂数据结构的现代 Web 应用来说尤为重要。MySQL 的 JSON 类型支持多种 JSON 函数，如 JSON_SET、JSON_INSERT、JSON_REPLACE 等，这些函数允许用户直接在数据库层面进行 JSON 文档的修改，无需将整个文档加载到应用层。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MariaDB 的 JSON 处理&lt;/strong&gt;：相比之下，MariaDB 采取了不同的策略。在 MariaDB 中，JSON 被视为 LONGTEXT 类型的一个别名，并通过 CHECK 约束来确保存储的数据是有效的 JSON 格式。这种方法虽然不如 MySQL 的原生 JSON 类型高效，但它提供了更高的灵活性。例如，用户可以在不更改表结构的情况下，将现有的 LONGTEXT 列转换为 JSON 类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;IP 地址和 UUID 列类型&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MariaDB 的创新&lt;/strong&gt;：MariaDB 在数据类型方面进行了一些创新，其中包括提供了专门的列类型来存储 IPv4 和 IPv6 地址，以及 UUID 值。这些类型分别为 INET_ATON、INET6_ATON 和 UUID。使用这些专用类型可以简化网络相关数据的存储和查询，同时提高性能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL 的传统处理&lt;/strong&gt;：在 MySQL 中，存储 IP 地址和 UUID 通常需要使用 VARCHAR 或 CHAR 类型，并依赖于应用层或数据库函数来进行格式验证和转换。这种方法虽然通用，但在处理大量网络数据时可能不够高效。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;数值列类型&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MySQL 的简化&lt;/strong&gt;：从 MySQL 8.0 版本开始，数值列类型不再关注显示宽度。这意味着，例如，INT(11) 和 INT 的存储空间和范围是相同的。这一变化旨在简化数据类型的使用，避免用户对显示宽度的误解。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MariaDB 的传统保留&lt;/strong&gt;：与此相反，MariaDB 仍然保留了数值列类型的显示宽度。这意味着在 MariaDB 中，INT(11) 和 INT 可能具有不同的含义，尤其是在进行数据迁移或模式兼容性测试时需要特别注意。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="7"&gt;
&lt;li&gt;&lt;strong&gt;时间列类型&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;处理 Y2K38 问题&lt;/strong&gt;：Y2K38 问题是指 32 位时间戳在 2038 年 1 月 19 日将达到其最大值，从而导致日期和时间处理上的问题。MariaDB 通过提供 TIMESTAMP 类型的新存储格式来解决这个问题，该格式支持更大的时间范围。而 MySQL 则依赖于用户自行处理这个问题，例如通过使用 BIGINT 类型来存储时间戳。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="9"&gt;
&lt;li&gt;&lt;strong&gt;空间列类型&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;空间数据支持&lt;/strong&gt;：MySQL 和 MariaDB 都提供了空间列类型，如 POINT、LINESTRING、POLYGON 等，用于存储地理空间数据。然而，在空间参考系统（SRID）的支持上，MySQL 提供了更广泛的选择，这使得它在处理复杂的空间数据时更具优势。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="11"&gt;
&lt;li&gt;&lt;strong&gt;字符集和校对规则&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;差异显著&lt;/strong&gt;：字符集和校对规则是数据库国际化支持的重要组成部分。在这两个方面，MySQL 和 MariaDB 存在显著差异。MariaDB 提供了一些 MySQL 不支持的字符集和校对规则，这使得它在处理特定语言和字符集时更加灵活。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二压缩功能对比"&gt;&lt;a href="#%e4%ba%8c%e5%8e%8b%e7%bc%a9%e5%8a%9f%e8%83%bd%e5%af%b9%e6%af%94" class="header-anchor"&gt;&lt;/a&gt;二、压缩功能对比
&lt;/h2&gt;&lt;p&gt;数据库压缩是提高存储效率、降低存储成本的重要手段。MySQL 和 MariaDB 在压缩功能上都进行了创新和优化，但各有侧重点。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-09-09-shu-ju-ku-xuan-xing-bi-kan-mysql-yu-mariadb-gong-neng-dui-bi/002-7e5a2535.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MySQL 的压缩技术&lt;/strong&gt;：MySQL 支持 InnoDB 存储引擎的传统压缩表，这种压缩可以显著减少磁盘空间的使用。在创建表时，可以通过指定&lt;code&gt;ROW_FORMAT=COMPRESSED&lt;/code&gt;来启用压缩。这种压缩技术在处理大量静态数据或归档数据时尤其有效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MariaDB 的列级压缩&lt;/strong&gt;：MariaDB 不仅支持 InnoDB 的压缩表，还引入了列级压缩功能。这意味着用户可以针对表中的特定列进行压缩，而不是整个行。这种精细化的压缩策略可以在节省存储空间的同时，减少对性能的影响。列级压缩特别适合于那些具有不同数据访问模式的大型表，可以针对不常访问或数据重复性高的列进行压缩。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="三默认值和生成列的差异"&gt;&lt;a href="#%e4%b8%89%e9%bb%98%e8%ae%a4%e5%80%bc%e5%92%8c%e7%94%9f%e6%88%90%e5%88%97%e7%9a%84%e5%b7%ae%e5%bc%82" class="header-anchor"&gt;&lt;/a&gt;三、默认值和生成列的差异
&lt;/h2&gt;&lt;p&gt;默认值和生成列是数据库设计中的重要概念，它们可以帮助确保数据的完整性和一致性。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;默认值的使用&lt;/strong&gt;：在 MySQL 和 MariaDB 中，都可以为列指定默认值。这些默认值可以是常量，也可以是复杂的表达式。然而，两者在支持的函数和表达式方面存在差异。例如，MySQL 可能支持某些特定的内置函数作为默认值，而 MariaDB 则可能不支持。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成列的特性&lt;/strong&gt;：生成列是 MariaDB 5.2 版本引入的特性，MySQL 从 5.7 版本开始也支持这一特性。生成列的值是由表中其他列的值计算得出的，这意味着它们是虚拟的，不需要实际存储在磁盘上。生成列在处理计算字段时非常有用，可以减少应用层的计算负担。不过，MySQL 和 MariaDB 在生成列的实现细节上有所不同，例如在支持的函数和表达式方面。&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="四外键和-check-约束的应用"&gt;&lt;a href="#%e5%9b%9b%e5%a4%96%e9%94%ae%e5%92%8c-check-%e7%ba%a6%e6%9d%9f%e7%9a%84%e5%ba%94%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;四、外键和 CHECK 约束的应用
&lt;/h2&gt;&lt;p&gt;外键和 CHECK 约束是保证数据库数据完整性的重要工具。它们在 MySQL 和 MariaDB 中的实现和应用有所不同。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;外键约束&lt;/strong&gt;：MySQL 和 MariaDB 都支持外键约束，用于强制执行表之间的关系。然而，两者在外键约束的语法、性能和错误处理上存在差异。例如，MariaDB 在某些情况下可能提供了更灵活的外键约束选项。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CHECK 约束&lt;/strong&gt;：CHECK 约束用于限制列的取值范围。在 MySQL 8.0 之前，CHECK 约束是语法糖，并不实际执行。而从 MySQL 8.0 开始，CHECK 约束得到了实际的支持。MariaDB 则一直支持 CHECK 约束，并且在某些情况下提供了更丰富的功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="五其他功能差异"&gt;&lt;a href="#%e4%ba%94%e5%85%b6%e4%bb%96%e5%8a%9f%e8%83%bd%e5%b7%ae%e5%bc%82" class="header-anchor"&gt;&lt;/a&gt;五、其他功能差异
&lt;/h2&gt;&lt;p&gt;除了上述差异外，MySQL 和 MariaDB 在许多其他功能上也存在差异，这些差异在某些特定场景下可能非常关键。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统版本化表&lt;/strong&gt;：MariaDB 提供了系统版本化表的功能，允许用户查询数据的历史版本。这对于需要跟踪数据变更历史的应用非常有用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;应用时间周期表&lt;/strong&gt;：这是 MariaDB 的一个独特功能，允许用户定义数据的有效时间范围。这种表对于处理具有时间限制的数据非常有用，例如合同、订阅和价格信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;二时态表&lt;/strong&gt;：MariaDB 的二时态表功能允许用户查询数据的历史状态，这对于历史数据分析非常有用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="六操作差异分析"&gt;&lt;a href="#%e5%85%ad%e6%93%8d%e4%bd%9c%e5%b7%ae%e5%bc%82%e5%88%86%e6%9e%90" class="header-anchor"&gt;&lt;/a&gt;六、操作差异分析
&lt;/h2&gt;&lt;p&gt;在实际操作中，MySQL 和 MariaDB 在执行 DDL 操作时存在一些差异，这些差异可能会影响到数据库的性能和可用性。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ALTER TABLE 操作&lt;/strong&gt;：ALTER TABLE 是数据库维护中常见的操作，用于修改表结构。MySQL 和 MariaDB 在执行 ALTER TABLE 操作时，尤其是在线 DDL 变更方面，存在差异。例如，MariaDB 的 ALGORITHM 选项允许用户控制 DDL 操作的执行方式，而 MySQL 则提供了 INSTANT 算法来减少 DDL 操作对性能的影响。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;索引构建&lt;/strong&gt;：在创建索引时，MySQL 8.0.27+支持并行构建索引，这可以显著提高索引创建的速度。而 MariaDB 在索引构建方面的优化则有所不同，它可能提供了不同的性能特点和选项。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DROP TABLE 操作&lt;/strong&gt;：在某些情况下，MySQL 在执行 DROP TABLE 操作时可能会遇到与 InnoDB 缓冲池大小相关的问题，导致系统停滞。MariaDB 则可能通过不同的机制来避免这些问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="七模式元数据差异"&gt;&lt;a href="#%e4%b8%83%e6%a8%a1%e5%bc%8f%e5%85%83%e6%95%b0%e6%8d%ae%e5%b7%ae%e5%bc%82" class="header-anchor"&gt;&lt;/a&gt;七、模式元数据差异
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-09-09-shu-ju-ku-xuan-xing-bi-kan-mysql-yu-mariadb-gong-neng-dui-bi/003-85a1cea8.png"&gt;&lt;/p&gt;
&lt;p&gt;数据库的模式元数据是数据库结构的信息，它对于数据库工具和监控系统的兼容性至关重要。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;信息模式表&lt;/strong&gt;：MySQL 和 MariaDB 在信息模式表（INFORMATION_SCHEMA）中提供的信息存在差异。这些差异可能会影响到依赖于这些信息的数据库工具和脚本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SHOW 查询&lt;/strong&gt;：SHOW 查询是获取数据库状态和配置信息的常用方法。在 MySQL 和 MariaDB 中，SHOW 查询返回的结果可能会有所不同，这可能会影响到数据库监控和管理工具。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="八结论与建议"&gt;&lt;a href="#%e5%85%ab%e7%bb%93%e8%ae%ba%e4%b8%8e%e5%bb%ba%e8%ae%ae" class="header-anchor"&gt;&lt;/a&gt;八、结论与建议
&lt;/h2&gt;&lt;p&gt;通过上述分析，我们可以看到，尽管 MySQL 和 MariaDB 在许多方面都非常相似，但它们在表格定义、DDL 操作、功能特性和性能优化上都有各自的特点和优势。对于数据库管理员和开发者来说，了解这些差异对于选择合适的数据库系统至关重要。&lt;/p&gt;
&lt;p&gt;以下是一些基于本文分析的结论和建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;选择合适的数据库&lt;/strong&gt;：如果你的应用需要处理大量的 JSON 数据，或者你更倾向于使用原生的 JSON 类型，那么 MySQL 可能是更好的选择。相反，如果你的应用需要处理 IP 地址和 UUID 数据，并且希望使用列级压缩，MariaDB 可能更适合你的需求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;考虑兼容性问题&lt;/strong&gt;：在进行数据库迁移时，兼容性是一个重要的考虑因素。如果你的应用依赖于特定的字符集或校对规则，或者使用了特定的 DDL 操作，那么在迁移前进行详细的兼容性测试是非常重要的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能优化&lt;/strong&gt;：对于性能敏感的应用，了解不同数据库系统的性能特点是非常关键的。例如，MySQL 的并行索引构建和 MariaDB 的列级压缩都可以显著提高性能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持续学习和关注&lt;/strong&gt;：数据库技术是不断发展的，新的版本可能会引入新的特性和改进。因此，持续学习和关注 MySQL 和 MariaDB 的发展动态，可以帮助你更好地利用这些数据库系统。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="结语"&gt;&lt;a href="#%e7%bb%93%e8%af%ad" class="header-anchor"&gt;&lt;/a&gt;结语
&lt;/h2&gt;&lt;p&gt;数据库的选择和管理是一个复杂的过程，需要综合考虑多种因素。希望本文能够为你提供关于 MySQL 和 MariaDB 在表格定义和数据定义语言方面的差异的深入理解，并在你的数据库设计和维护工作中提供帮助。无论是选择 MySQL 还是 MariaDB，关键是要确保所选的数据库系统能够满足你的业务需求，同时提供良好的性能和可扩展性。&lt;/p&gt;</description></item><item><title>数据库分片：是什么？如何运作？</title><link>https://xiaobox.github.io/p/2024-08-30-shu-ju-ku-fen-pian-shi-shen-me-ru-he-yun-zuo/</link><pubDate>Fri, 30 Aug 2024 23:00:00 +0000</pubDate><guid>https://xiaobox.github.io/p/2024-08-30-shu-ju-ku-fen-pian-shi-shen-me-ru-he-yun-zuo/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-08-30-shu-ju-ku-fen-pian-shi-shen-me-ru-he-yun-zuo/cover.jpg" alt="Featured image of post 数据库分片：是什么？如何运作？" /&gt;&lt;h2 id="数据库分片概念与实现"&gt;&lt;a href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e5%88%86%e7%89%87%e6%a6%82%e5%bf%b5%e4%b8%8e%e5%ae%9e%e7%8e%b0" class="header-anchor"&gt;&lt;/a&gt;数据库分片：概念与实现
&lt;/h2&gt;&lt;p&gt;在现代应用程序中，数据库的性能和可扩展性至关重要。随着用户数量的增加和数据量的激增，传统的单一数据库架构往往无法满足需求。这时，&lt;strong&gt;数据库分片&lt;/strong&gt;（Sharding）作为一种有效的解决方案，逐渐被广泛采用。本文将深入探讨数据库分片的概念、工作原理、实施策略以及常用工具，帮助读者理解如何通过分片来提升数据库性能和可扩展性。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-08-30-shu-ju-ku-fen-pian-shi-shen-me-ru-he-yun-zuo/001-0c0bc74e.png"&gt;&lt;/p&gt;
&lt;h3 id="什么是数据库分片"&gt;&lt;a href="#%e4%bb%80%e4%b9%88%e6%98%af%e6%95%b0%e6%8d%ae%e5%ba%93%e5%88%86%e7%89%87" class="header-anchor"&gt;&lt;/a&gt;什么是数据库分片？
&lt;/h3&gt;&lt;p&gt;数据库分片是一种将数据分散存储在多个服务器上的策略，而不是将所有数据集中在一个庞大的数据库中。每个数据分区称为一个&lt;strong&gt;分片&lt;/strong&gt;（Shard）。通过将数据库拆分成多个分片，可以有效降低单个数据库的负载，从而提升整体性能。&lt;/p&gt;
&lt;p&gt;例如，在一个用户表中，如果所有用户数据都存储在一台服务器上，随着用户数量的增加，查询和写入操作的性能将受到影响。通过分片，可以将用户数据分布到多台服务器上，每台服务器只处理其对应的用户数据，从而提高响应速度和处理能力。&lt;/p&gt;
&lt;h3 id="数据库分片的必要性"&gt;&lt;a href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e5%88%86%e7%89%87%e7%9a%84%e5%bf%85%e8%a6%81%e6%80%a7" class="header-anchor"&gt;&lt;/a&gt;数据库分片的必要性
&lt;/h3&gt;&lt;p&gt;随着业务的发展，许多公司发现单一数据库的扩展性有限。以下是一些常见的场景，说明何时需要考虑数据库分片：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;频繁的性能瓶颈&lt;/strong&gt;：当数据库频繁出现性能瓶颈，导致响应时间延长时，分片可以帮助分散负载。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数据量激增&lt;/strong&gt;：当数据量迅速增长，单一数据库无法存储或处理时，分片可以将数据分散到多个服务器上。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;高并发访问&lt;/strong&gt;：在高并发访问场景下，分片能够有效分散请求，减少单一数据库的压力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;地理分布&lt;/strong&gt;：在全球范围内运营的应用程序可能需要将数据存储在不同地区，以降低延迟。通过分片，可以将数据分布在离用户更近的服务器上。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="数据库分片的工作原理"&gt;&lt;a href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e5%88%86%e7%89%87%e7%9a%84%e5%b7%a5%e4%bd%9c%e5%8e%9f%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;数据库分片的工作原理
&lt;/h3&gt;&lt;p&gt;实现数据库分片需要考虑几个关键步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;选择分片方案&lt;/strong&gt;：决定哪些数据需要分片，如何组织这些数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;组织目标基础设施&lt;/strong&gt;：确定将数据分片到多少台服务器上，以及每台服务器上存储多少数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;创建路由层&lt;/strong&gt;：设计应用程序如何知道新数据存储的位置，以及如何查询现有数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;规划和执行迁移&lt;/strong&gt;：如何在最小的停机时间内，从单一数据库迁移到多个数据库。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="分片方案与算法"&gt;&lt;a href="#%e5%88%86%e7%89%87%e6%96%b9%e6%a1%88%e4%b8%8e%e7%ae%97%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;分片方案与算法
&lt;/h3&gt;&lt;p&gt;选择合适的分片方案是成功实施分片的关键。以下是几种常见的分片策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基于哈希的分片&lt;/strong&gt;：通过对某个列的值进行哈希处理，将哈希值相同的数据存储在同一服务器上。此方法能够有效地均匀分布数据，但可能会导致某些查询变得复杂。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基于范围的分片&lt;/strong&gt;：选择一个列，创建范围，将数据分配到不同的分片中。适合于数值列的均匀分布，例如按用户 ID 范围分片。此方法的缺点是可能导致某些分片的数据量不均。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基于目录的分片&lt;/strong&gt;：手动选择列，分配分片，并维护一个查找表，以便知道每行数据存储的位置。这种方法灵活性高，但维护成本较大。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;混合分片&lt;/strong&gt;：结合以上几种方法，根据实际需求灵活选择分片策略。例如，可以先使用哈希分片，然后在某些情况下使用范围分片。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;选择分片方案时，需要考虑业务模型和查询负载的分布。例如，对于 B2B SaaS 公司，按组织划分数据可能更为合理；而对于消费者公司，随机哈希分片可能更有效。&lt;/p&gt;
&lt;h3 id="服务器选择与配置"&gt;&lt;a href="#%e6%9c%8d%e5%8a%a1%e5%99%a8%e9%80%89%e6%8b%a9%e4%b8%8e%e9%85%8d%e7%bd%ae" class="header-anchor"&gt;&lt;/a&gt;服务器选择与配置
&lt;/h3&gt;&lt;p&gt;在确定分片方案后，接下来需要决定使用多少台服务器来存储数据。这个决策取决于预算、未来数据库负载的预测以及云服务提供商的选择。&lt;/p&gt;
&lt;p&gt;一种常见的方法是&lt;strong&gt;最大化灵活性&lt;/strong&gt;。可以从少量服务器开始，随着需求的增加逐步扩展。在添加新服务器时，需要重新平衡分片，以确保数据均匀分布。&lt;/p&gt;
&lt;h4 id="服务器配置"&gt;&lt;a href="#%e6%9c%8d%e5%8a%a1%e5%99%a8%e9%85%8d%e7%bd%ae" class="header-anchor"&gt;&lt;/a&gt;服务器配置
&lt;/h4&gt;&lt;p&gt;在配置服务器时，需要考虑以下几个方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;硬件配置&lt;/strong&gt;：选择合适的 CPU、内存和存储设备，以满足预期的负载需求。高性能的 SSD 存储可以显著提高数据库的读写速度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;网络带宽&lt;/strong&gt;：确保服务器之间的网络连接速度足够快，以减少数据传输的延迟。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;备份与恢复&lt;/strong&gt;：设计合理的备份策略，以防止数据丢失。可以使用定期备份和增量备份相结合的方法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;监控与报警&lt;/strong&gt;：配置监控工具，实时监测数据库的性能指标，如 CPU 使用率、内存使用情况和磁盘 I/O 等。一旦出现异常情况，及时报警并采取措施。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="路由分片查询"&gt;&lt;a href="#%e8%b7%af%e7%94%b1%e5%88%86%e7%89%87%e6%9f%a5%e8%af%a2" class="header-anchor"&gt;&lt;/a&gt;路由分片查询
&lt;/h3&gt;&lt;p&gt;当数据分布在多个数据库中时，如何让应用程序知道查询哪个数据库呢？这需要构建一个路由层。通常，这种逻辑是在应用程序层实现的。&lt;/p&gt;
&lt;p&gt;例如，可以通过以下伪代码实现路由逻辑：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;route_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sharding_key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;database_1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sharding_keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;connect_to_database_1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sharding_key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;database_2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sharding_keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;connect_to_database_2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Data not found in any database&amp;#34;&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;p&gt;这种逻辑可以相对简单地存储在配置文件或数据库的查找表中。重要的是要确保应用程序能够根据数据的分片键找到相应的数据库。&lt;/p&gt;
&lt;h3 id="迁移到分片解决方案"&gt;&lt;a href="#%e8%bf%81%e7%a7%bb%e5%88%b0%e5%88%86%e7%89%87%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;迁移到分片解决方案
&lt;/h3&gt;&lt;p&gt;在完成上述步骤并确保服务器正常运行后，接下来面临的挑战是如何在最小的停机时间内进行迁移。迁移到分片架构通常比迁移到单一新数据库提供商复杂得多，因为可能出现多种问题。&lt;/p&gt;
&lt;h4 id="迁移步骤"&gt;&lt;a href="#%e8%bf%81%e7%a7%bb%e6%ad%a5%e9%aa%a4" class="header-anchor"&gt;&lt;/a&gt;迁移步骤
&lt;/h4&gt;&lt;p&gt;Notion 的工程团队提出了一种有效的迁移框架，具体步骤包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;双写&lt;/strong&gt;：将新数据同时写入旧数据库和新数据库。这一过程可以在一定时间内并行进行，以确保新旧数据的一致性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;回填&lt;/strong&gt;：在开始双写后，将旧数据迁移到新数据库。这一过程可能需要根据数据量的大小分批进行，以避免对系统性能的影响。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;验证&lt;/strong&gt;：确保新数据库中的数据完整性。可以通过对比新旧数据库的数据记录，确保没有遗漏或错误。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;切换&lt;/strong&gt;：实际切换到新数据库，可以逐步进行，例如先进行双读，再迁移所有读取操作。切换后，监控新数据库的性能，确保其正常运行。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="分片框架与工具"&gt;&lt;a href="#%e5%88%86%e7%89%87%e6%a1%86%e6%9e%b6%e4%b8%8e%e5%b7%a5%e5%85%b7" class="header-anchor"&gt;&lt;/a&gt;分片框架与工具
&lt;/h3&gt;&lt;p&gt;尽管许多团队会从头开始构建分片架构，但也有一些成熟的工具可以帮助实现分片。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vitess&lt;/strong&gt;：最初为 YouTube 开发的 Vitess，现已成为一个开源项目，提供了 MySQL 的分片解决方案，并支持连接池、动态重新分片和监控工具等功能。Vitess 通过将数据分片到多个 MySQL 实例中，解决了大规模数据存储的问题。&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-08-30-shu-ju-ku-fen-pian-shi-shen-me-ru-he-yun-zuo/002-0047e39d.png"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Citus&lt;/strong&gt;：为 Postgres 提供分片支持的开源扩展，能够在单节点或多个节点上运行，适合需要分片的 Postgres 用户。Citus 允许用户将 Postgres 数据库水平扩展，并提供了查询路由和分片管理的功能。&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2024-08-30-shu-ju-ku-fen-pian-shi-shen-me-ru-he-yun-zuo/003-e382f694.png"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;无服务器数据库&lt;/strong&gt;：近年来，许多“无服务器”数据库逐渐兴起，例如 CockroachDB 和 Google Cloud Spanner，这些数据库本身内置了分片功能，简化了开发者的工作。这些数据库能够自动处理数据分片和负载均衡，极大地降低了运维成本。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="分片的挑战与解决方案"&gt;&lt;a href="#%e5%88%86%e7%89%87%e7%9a%84%e6%8c%91%e6%88%98%e4%b8%8e%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;分片的挑战与解决方案
&lt;/h3&gt;&lt;p&gt;尽管数据库分片能够带来许多好处，但在实施过程中也面临一些挑战。以下是一些常见的挑战及其解决方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数据不均衡&lt;/strong&gt;：在某些情况下，数据可能会在分片之间分布不均，导致某些分片的负载过重。解决方案是定期监测数据分布情况，并根据需要进行重新分片。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;复杂的查询&lt;/strong&gt;：当查询涉及多个分片时，可能会导致复杂的查询逻辑。解决方案是优化查询，尽量减少跨分片的操作，或者在应用层实现聚合逻辑。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;故障恢复&lt;/strong&gt;：在分片架构中，单个分片的故障可能影响整体系统的可用性。解决方案是实现高可用性架构，例如使用主从复制或分布式一致性协议。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;运维成本&lt;/strong&gt;：管理多个分片可能增加运维成本。解决方案是使用自动化工具来简化运维流程，例如使用监控工具和自动化备份工具。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="未来发展趋势"&gt;&lt;a href="#%e6%9c%aa%e6%9d%a5%e5%8f%91%e5%b1%95%e8%b6%8b%e5%8a%bf" class="header-anchor"&gt;&lt;/a&gt;未来发展趋势
&lt;/h3&gt;&lt;p&gt;随着技术的不断进步，数据库分片的概念和实现也在不断演化。以下是一些未来的发展趋势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;智能分片&lt;/strong&gt;：未来的数据库系统可能会采用机器学习算法，根据实时数据访问模式自动调整分片策略，以实现更高的性能和可扩展性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;多模型数据库&lt;/strong&gt;：随着对多样化数据存储需求的增加，未来的数据库可能会支持多种数据模型（如关系型、文档型、图形型等），并能够在同一系统中实现分片。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;云原生数据库&lt;/strong&gt;：随着云计算的普及，越来越多的数据库将采用云原生架构，自动处理分片、负载均衡和故障恢复等任务，降低开发者的运维负担。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;边缘计算与分片&lt;/strong&gt;：随着物联网和边缘计算的发展，未来的数据库可能会在边缘设备上实现分片，以降低延迟并提高数据处理效率。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="结论"&gt;&lt;a href="#%e7%bb%93%e8%ae%ba" class="header-anchor"&gt;&lt;/a&gt;结论
&lt;/h3&gt;&lt;p&gt;数据库分片是一种强大的技术，可以帮助企业在面对大规模数据和高并发请求时提升性能和可扩展性。通过合理选择分片方案、配置服务器、构建路由层以及规划迁移策略，企业可以有效地实现数据库的分片架构。随着技术的不断发展，分片工具和框架也在不断成熟，未来将为更多企业提供便利。在实施分片时，企业应根据自身业务需求和数据特点，灵活选择合适的分片策略，以确保系统的高效运行。&lt;/p&gt;
&lt;p&gt;通过本文的深入探讨，希望读者能够全面理解数据库分片的概念和实现方法，并在实际应用中有效应用这一技术，提升数据库的性能和可扩展性。无论是初创企业还是大型企业，合理的数据库分片策略都将为其业务发展提供强有力的支持。&lt;/p&gt;</description></item><item><title>关于 Redis 的有趣的知识</title><link>https://xiaobox.github.io/p/2023-12-01-guan-yu-redis-de-you-qu-de-zhi-shi/</link><pubDate>Fri, 01 Dec 2023 08:25:22 +0000</pubDate><guid>https://xiaobox.github.io/p/2023-12-01-guan-yu-redis-de-you-qu-de-zhi-shi/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-12-01-guan-yu-redis-de-you-qu-de-zhi-shi/cover.jpg" alt="Featured image of post 关于 Redis 的有趣的知识" /&gt;&lt;h1 id="关于-redis-的有趣的知识"&gt;&lt;a href="#%e5%85%b3%e4%ba%8e-redis-%e7%9a%84%e6%9c%89%e8%b6%a3%e7%9a%84%e7%9f%a5%e8%af%86" class="header-anchor"&gt;&lt;/a&gt;关于 Redis 的有趣的知识
&lt;/h1&gt;&lt;p&gt;有序集合的英文全称明明是 sorted sets，为啥叫 zset 呢？&lt;/p&gt;
&lt;p&gt;Redis官网上没有解释，但是在 Github 上有人向作者提问了。&lt;/p&gt;
&lt;p&gt;作者是这么回答的：&lt;/p&gt;
&lt;p&gt;Hello. Z is as in XYZ, so the idea is, sets with another dimension: the order. It’s a far association… I know 😃&lt;/p&gt;
&lt;p&gt;原来前面的 Z 代表的是 XYZ 中的Z，zset 是在说这是比 set 有更多一个维度的 set 😦&lt;/p&gt;
&lt;p&gt;是不没道理？&lt;/p&gt;
&lt;p&gt;更没道理的还有，Redis 默认端口 6379 ，因为作者喜欢的一个叫 Merz 的女明星，其名字在手机上输入正好对应号码 6379，索性就把 Redis 的默认端口叫 6379 了…&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-12-01-guan-yu-redis-de-you-qu-de-zhi-shi/001-83277fc0.jpg"&gt;&lt;/p&gt;
&lt;p&gt;小盒子的技术分享&lt;/p&gt;</description></item><item><title>一条SQL 最多能查询出来多少条记录？</title><link>https://xiaobox.github.io/p/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/</link><pubDate>Fri, 14 Jul 2023 04:16:40 +0000</pubDate><guid>https://xiaobox.github.io/p/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/cover.jpg" alt="Featured image of post 一条SQL 最多能查询出来多少条记录？" /&gt;&lt;h2 id="问题"&gt;&lt;a href="#%e9%97%ae%e9%a2%98" class="header-anchor"&gt;&lt;/a&gt;问题
&lt;/h2&gt;&lt;p&gt;一条这样的 SQL 语句能查询出多少条记录？&lt;/p&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="ln"&gt;1&lt;/span&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="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;表中有 100 条记录的时候能全部查询出来返回给客户端吗？&lt;/p&gt;
&lt;p&gt;如果记录数是 1w 呢？10w 呢？100w 、1000w 呢？&lt;/p&gt;
&lt;p&gt;虽然在实际业务操作中我们不会这么干，尤其对于数据量大的表不会这样干，但这是个值得想一想的问题。&lt;/p&gt;
&lt;h2 id="寻找答案"&gt;&lt;a href="#%e5%af%bb%e6%89%be%e7%ad%94%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;寻找答案
&lt;/h2&gt;&lt;p&gt;前提：以下所涉及资料全部基于 MySQL 8&lt;/p&gt;
&lt;h3 id="max_allowed_packet"&gt;&lt;a href="#max_allowed_packet" class="header-anchor"&gt;&lt;/a&gt;max_allowed_packet
&lt;/h3&gt;&lt;p&gt;在查询资料的过程中发现了这个参数 &lt;code&gt;max_allowed_packet&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/001-5dd1c370.png"&gt;&lt;/p&gt;
&lt;p&gt;上图参考了 MySQL 的官方文档，根据文档我们知道：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MySQL 客户端 &lt;code&gt;max_allowed_packet&lt;/code&gt; 值的默认大小为 16M（不同的客户端可能有不同的默认值，但最大不能超过 1G）&lt;/li&gt;
&lt;li&gt;MySQL 服务端 &lt;code&gt;max_allowed_packet&lt;/code&gt; 值的默认大小为 64M&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max_allowed_packet&lt;/code&gt; 值最大可以设置为 1G（1024 的倍数）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然而 根据上图的文档中所述&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“&lt;/p&gt;
&lt;p&gt;The maximum size of one packet or any generated/intermediate string,or any parameter sent by the mysql_smt_send_long_data() C API function&lt;/p&gt;
&lt;p&gt;”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;one packet&lt;/li&gt;
&lt;li&gt;generated/intermediate string&lt;/li&gt;
&lt;li&gt;any parameter sent by the mysql_smt_send_long_data() C API function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这三个东东具体都是什么呢？&lt;code&gt;packet&lt;/code&gt; 到底是结果集大小，还是网络包大小还是什么？于是 google 了一下，搜索排名第一的是这个：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/002-7826aeed.png"&gt;&lt;/p&gt;
&lt;p&gt;根据 “Packet Too Large” 的说明， 通信包 (communication packet) 是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个被发送到 MySQL 服务器的单个 SQL 语句&lt;/li&gt;
&lt;li&gt;或者是一个被发送到客户端的单行记录&lt;/li&gt;
&lt;li&gt;或者是一个从主服务器 (replication source server) 被发送到从属服务器 (replica) 的二进制日志事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;1、3 点好理解，这也同时解释了，如果你发送的一条 SQL 语句特别大可能会执行不成功的原因，尤其是&lt;code&gt;insert&lt;/code&gt; &lt;code&gt;update&lt;/code&gt; 这种，单个 SQL 语句不是没有上限的，不过这种情况一般不是因为 SQL 语句写的太长，主要是由于某个字段的值过大，比如有 BLOB 字段。&lt;/p&gt;
&lt;p&gt;那么第 2 点呢，单行记录，默认值是 64M，会不会太大了啊，一行记录有可能这么大的吗？有必要设置这么大吗？单行最大存储空间限制又是多少呢？&lt;/p&gt;
&lt;h3 id="单行最大存储空间"&gt;&lt;a href="#%e5%8d%95%e8%a1%8c%e6%9c%80%e5%a4%a7%e5%ad%98%e5%82%a8%e7%a9%ba%e9%97%b4" class="header-anchor"&gt;&lt;/a&gt;单行最大存储空间
&lt;/h3&gt;&lt;p&gt;MySQL 单行最大宽度是 65535 个字节，也就是 64KB 。无论是 InnoDB 引擎还是 MyISAM 引擎。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/003-fc3ce2e6.png"&gt;&lt;/p&gt;
&lt;p&gt;通过上图可以看到 超过 65535 不行，不过请注意其中的错误提示：“Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535” ，如果字段是变长类型的如 BLOB 和 TEXT 就不包括了，那么我们试一下用和上图一样的字段长度，只把最后一个字段的类型改成 BLOB 和 TEXT&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;mysql&amp;gt; CREATE TABLE t (a VARCHAR(10000), b VARCHAR(10000),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; f VARCHAR(10000), g TEXT(6000)) ENGINE=InnoDB CHARACTER SET latin1;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.02 sec)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可见无论 是改成 BLOB 还是 TEXT 都可以成功。但这里请注意，字符集是 &lt;code&gt;latin1&lt;/code&gt; 可以成功，如果换成 &lt;code&gt;utf8mb4&lt;/code&gt; 或者 &lt;code&gt;utf8mb3&lt;/code&gt; 就不行了，会报错，仍然是 ：“Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535.” 为什么呢？&lt;/p&gt;
&lt;p&gt;因为虽然不包括 TEXT 和 BLOB, 但总长度还是超了！&lt;/p&gt;
&lt;p&gt;我们先看一下这个熟悉的 VARCHAR(255) ， 你有没有想过为什么用 255，不用 256？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“&lt;/p&gt;
&lt;p&gt;在 4.0 版本以下，varchar(255) 指的是 255 个字节，使用 1 个字节存储长度即可。当大于等于 256 时，要使用 2 个字节存储长度。所以定义 varchar(255) 比 varchar(256) 更好。&lt;/p&gt;
&lt;p&gt;但是在 5.0 版本以上，varchar(255) 指的是 255 个字符，每个字符可能占用多个字节，例如使用 UTF8 编码时每个汉字占用 3 字节，使用 GBK 编码时每个汉字占 2 字节。&lt;/p&gt;
&lt;p&gt;”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;例子中我们用的是 MySQL8 ，由于字符集是 utf8mb3 ，存储一个字要用三个字节， 长度为 255 的话（列宽），总长度要 765 字节 ，再加上用 2 个字节存储长度，那么这个列的总长度就是 767 字节。所以用 latin1 可以成功，是因为一个字符对应一个字节，而 utf8mb3 或 utf8mb4 一个字符对应三个或四个字节，VARCHAR(10000) 就可能等于要占用 30000 多 40000 多字节，比原来大了 3、4 倍，肯定放不下了。&lt;/p&gt;
&lt;p&gt;另外，还有一个要求，列的宽度不要超过 MySQL 页大小 （默认 16K）的一半，要比一半小一点儿。例如，对于默认的 16KB &lt;code&gt;InnoDB&lt;/code&gt; 页面大小，最大行大小略小于 8KB。&lt;/p&gt;
&lt;p&gt;下面这个例子就是超过了一半，所以报错，当然解决办法也在提示中给出了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;mysql&amp;gt; CREATE TABLE t4 (
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt; c1 CHAR(255),c2 CHAR(255),c3 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt; c4 CHAR(255),c5 CHAR(255),c6 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt; c7 CHAR(255),c8 CHAR(255),c9 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt; c10 CHAR(255),c11 CHAR(255),c12 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt; c13 CHAR(255),c14 CHAR(255),c15 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; c16 CHAR(255),c17 CHAR(255),c18 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; c19 CHAR(255),c20 CHAR(255),c21 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt; c22 CHAR(255),c23 CHAR(255),c24 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; c25 CHAR(255),c26 CHAR(255),c27 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; c28 CHAR(255),c29 CHAR(255),c30 CHAR(255),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt; c31 CHAR(255),c32 CHAR(255),c33 CHAR(255)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt; ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC DEFAULT CHARSET latin1;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;ERROR 1118 (42000): Row size too large (&amp;gt; 8126). Changing some columns to TEXT or BLOB may help.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;In current row format, BLOB prefix of 0 bytes is stored inline.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;那么为什么是 8K，不是 7K，也不是 9K 呢？ 这么设计的原因可能是：MySQL 想让一个数据页中能存放更多的数据行，至少也得要存放两行数据（16K）。否则就失去了 B+Tree 的意义。B+Tree 会退化成一个低效的链表。&lt;/p&gt;
&lt;p&gt;你可能还会奇怪，不超过 8K ？你前面的例子明明都快 64K 也能存下，那 8K 到 64K 中间这部分怎么解释？&lt;/p&gt;
&lt;p&gt;答：如果包含可变长度列的行超过 &lt;code&gt;InnoDB&lt;/code&gt; 最大行大小， &lt;code&gt;InnoDB&lt;/code&gt; 会选择可变长度列进行页外存储，直到该行适合 &lt;code&gt;InnoDB&lt;/code&gt; ，这也就是为什么前面有超过 8K 的也能成功，那是因为用的是&lt;code&gt;VARCHAR&lt;/code&gt;这种可变长度类型。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/004-d87d64d7.png"&gt;&lt;/p&gt;
&lt;p&gt;当你往这个数据页中写入一行数据时，即使它很大将达到了数据页的极限，但是通过行溢出机制。依然能保证你的下一条数据还能写入到这个数据页中。&lt;/p&gt;
&lt;p&gt;我们通过 Compact 格式，简单了解一下什么是 &lt;code&gt;页外存储&lt;/code&gt; 和 &lt;code&gt;行溢出&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;MySQL8 InnoDB 引擎目前有 4 种 行记录格式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;REDUNDANT&lt;/li&gt;
&lt;li&gt;COMPACT&lt;/li&gt;
&lt;li&gt;DYNAMIC（默认 default 是这个）&lt;/li&gt;
&lt;li&gt;COMPRESSED&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;行记录格式&lt;/code&gt; 决定了其行的物理存储方式，这反过来又会影响查询和 DML 操作的性能。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/005-8bab65ff.png"&gt;&lt;/p&gt;
&lt;p&gt;Compact 格式的实现思路是：当列的类型为 VARCHAR、 VARBINARY、 BLOB、TEXT 时，该列超过 768byte 的数据放到其他数据页中去。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/006-c96aed44.png"&gt;&lt;/p&gt;
&lt;p&gt;在 MySQL 设定中，当 varchar 列长度达到 768byte 后，会将该列的前 768byte 当作当作 prefix 存放在行中，多出来的数据溢出存放到溢出页中，然后通过一个偏移量指针将两者关联起来，这就是 &lt;code&gt;行溢出&lt;/code&gt;机制&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“&lt;/p&gt;
&lt;p&gt;假如你要存储的数据行很大超过了 65532byte 那么你是写入不进去的。假如你要存储的单行数据小于 65535byte 但是大于 16384byte，这时你可以成功 insert，但是一个数据页又存储不了你插入的数据。这时肯定会行溢出！&lt;/p&gt;
&lt;p&gt;”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;MySQL 这样做，有效的防止了单个 varchar 列或者 Text 列太大导致单个数据页中存放的行记录过少的情况，避免了 IO 飙升的窘境。&lt;/p&gt;
&lt;h3 id="单行最大列数限制"&gt;&lt;a href="#%e5%8d%95%e8%a1%8c%e6%9c%80%e5%a4%a7%e5%88%97%e6%95%b0%e9%99%90%e5%88%b6" class="header-anchor"&gt;&lt;/a&gt;单行最大列数限制
&lt;/h3&gt;&lt;p&gt;mysql 单表最大列数也是有限制的，是 4096 ，但 InnoDB 是 1017&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/007-83736702.png"&gt;&lt;/p&gt;
&lt;h3 id="实验"&gt;&lt;a href="#%e5%ae%9e%e9%aa%8c" class="header-anchor"&gt;&lt;/a&gt;实验
&lt;/h3&gt;&lt;p&gt;前文中我们疑惑 &lt;code&gt;max_allowed_packet&lt;/code&gt; 在 MySQL8 的默认值是 64M，又说这是限制单行数据的，单行数据有这么大吗？在前文我们介绍了行溢出， 由于有了 &lt;code&gt;行溢出&lt;/code&gt; ，单行数据确实有可能比较大。&lt;/p&gt;
&lt;p&gt;那么还剩下一个问题，&lt;code&gt;max_allowed_packet&lt;/code&gt; 限制的确定是单行数据吗，难道不是查询结果集的大小吗 ? 下面我们做个实验，验证一下。&lt;/p&gt;
&lt;p&gt;建表&lt;/p&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="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c22&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c23&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c24&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c25&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c26&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c27&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c28&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c29&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c31&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;192&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ENGINE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;InnoDB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROW_FORMAT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;DYNAMIC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CHARSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;latin1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;经过测试虽然提示的是 &lt;code&gt;Row size too large (&amp;gt; 8126)&lt;/code&gt; 但如果全部长度加起来是 8126 建表不成功，最终我试到 8097 是能建表成功的。为什么不是 8126 呢 ？可能是还需要存储一些其他的东西占了一些字节吧，比如隐藏字段什么的。&lt;/p&gt;
&lt;p&gt;用存储过程造一些测试数据，把表中的所有列填满&lt;/p&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="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;create&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;definer&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;root&lt;/span&gt;&lt;span class="o"&gt;@`%`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;procedure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;generate_test_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DECLARE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;col_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPEAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DO&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;col_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;col_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;col_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;col_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPEAT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;192&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&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;i&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;WHILE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 &lt;code&gt;max_allowed_packet&lt;/code&gt; 设置的小一些，先用 &lt;code&gt;show VARIABLES like '%max_allowed_packet%';&lt;/code&gt; 看一下当前的大小，我的是 &lt;code&gt;67108864&lt;/code&gt; 这个单位是字节，等于 64M，然后用 &lt;code&gt;set global max_allowed_packet =1024&lt;/code&gt; 将它设置成允许的最小值 1024 byte。设置好后，关闭当前查询窗口再新建一个，然后再查看：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/008-6bdee1ca.png"&gt;&lt;/p&gt;
&lt;p&gt;这时我用 &lt;code&gt;select * from t1;&lt;/code&gt; 查询表数据时就会报错：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2023-07-14-yi-tiao-sql-zui-duo-neng-cha-xun-chu-lai-duo-shao-tiao-ji-lu/009-cdde1aef.png"&gt;&lt;/p&gt;
&lt;p&gt;因为我们一条记录的大小就是 8K 多了，所以肯定超过 1024byte。可见文档的说明是对的， &lt;code&gt;max_allowed_packet&lt;/code&gt; 确实是可以约束单行记录大小的。&lt;/p&gt;
&lt;h2 id="答案"&gt;&lt;a href="#%e7%ad%94%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;答案
&lt;/h2&gt;&lt;p&gt;文章写到这里，我有点儿写不下去了，一是因为懒，另外一个原因是关于这个问题：“一条 SQL 最多能查询出来多少条记录？” 肯定没有标准答案&lt;/p&gt;
&lt;p&gt;目前我们可以知道的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你的单行记录大小不能超过 &lt;code&gt;max_allowed_packet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;一个表最多可以创建 1017 列 （InnoDB）&lt;/li&gt;
&lt;li&gt;建表时定义列的固定长度不能超过 页的一半（8k,16k&amp;hellip;）&lt;/li&gt;
&lt;li&gt;建表时定义列的总长度不能超过 65535 个字节&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果这些条件我们都满足了，然后发出了一个没有 where 条件的全表查询 &lt;code&gt;select *&lt;/code&gt; 那么&amp;hellip;..&lt;/p&gt;
&lt;p&gt;首先，你我都知道，这种情况不会发生在生产环境的，如果真发生了，一定是你写错了，忘了加条件。因为几乎没有这种要查询出所有数据的需求。如果有，也不能开发，因为这不合理。&lt;/p&gt;
&lt;p&gt;我考虑的也就是个理论情况，从理论上讲能查询出多少数据不是一个确定的值，除了前文提到的一些条件外，它肯定与以下几项有直接的关系&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据库的可用内存&lt;/li&gt;
&lt;li&gt;数据库内部的缓存机制，比如缓存区的大小&lt;/li&gt;
&lt;li&gt;数据库的查询超时机制&lt;/li&gt;
&lt;li&gt;应用的可用物理内存&lt;/li&gt;
&lt;li&gt;&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;说到这儿，我确实可以再做个实验验证一下，但因为懒就不做了，大家有兴趣可以自己设定一些条件做个实验试一下，比如在特定内存和特定参数的情况下，到底能查询出多少数据，就能看得出来了。&lt;/p&gt;
&lt;p&gt;虽然我没能给出文章开头问题的答案，但通过寻找答案也弄清楚了 MySQL 的一些限制条件，并加以了验证，也算是有所收获了。&lt;/p&gt;
&lt;h2 id="参考"&gt;&lt;a href="#%e5%8f%82%e8%80%83" class="header-anchor"&gt;&lt;/a&gt;参考
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://dev.mysql.com/doc/refman/8.0/en/packet-too-large.html" target="_blank" rel="noopener"
 &gt;https://dev.mysql.com/doc/refman/8.0/en/packet-too-large.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar" target="_blank" rel="noopener"
 &gt;https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar&lt;/a&gt;_max_allowed_packet&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.cnblogs.com/ZhuChangwu/p/14035330.html" target="_blank" rel="noopener"
 &gt;https://www.cnblogs.com/ZhuChangwu/p/14035330.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://dev.mysql.com/doc/refman/8.0/en/column-count-limit.html" target="_blank" rel="noopener"
 &gt;https://dev.mysql.com/doc/refman/8.0/en/column-count-limit.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MySQL B+树叶子结点使用单向链表进行串连？错！</title><link>https://xiaobox.github.io/p/2022-05-20-mysql-b-shu-ye-zi-jie-dian-shi-yong-dan-xiang-lian-biao-jin/</link><pubDate>Fri, 20 May 2022 04:15:49 +0000</pubDate><guid>https://xiaobox.github.io/p/2022-05-20-mysql-b-shu-ye-zi-jie-dian-shi-yong-dan-xiang-lian-biao-jin/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-05-20-mysql-b-shu-ye-zi-jie-dian-shi-yong-dan-xiang-lian-biao-jin-/cover.jpg" alt="Featured image of post MySQL B+树叶子结点使用单向链表进行串连？错！" /&gt;&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="372px" data-flex-grow="155" height="537" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://xiaobox.github.io/p/2022-05-20-mysql-b-shu-ye-zi-jie-dian-shi-yong-dan-xiang-lian-biao-jin/001-cca6a65b.jpg" width="833"&gt;&lt;/p&gt;
&lt;p&gt;先看一下上面这个图，大家是不是觉得没什么毛病？&lt;/p&gt;
&lt;p&gt;如题，就是叶子结点用单向链表连接起来是吧。&lt;/p&gt;
&lt;p&gt;很多文章是这么讲的，很多图也是这么画的，但其实不正确，或者说不严谨。&lt;/p&gt;
&lt;p&gt;正确的说法应该是：B+ 树中各个页之间是通过双向链表连接的，叶子节点中的数据是通过单向链表连接的&lt;/p&gt;
&lt;p&gt;我们来看下正确的图：&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="330px" data-flex-grow="137" height="680" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://xiaobox.github.io/p/2022-05-20-mysql-b-shu-ye-zi-jie-dian-shi-yong-dan-xiang-lian-biao-jin/002-d1ced06d.jpg" width="936"&gt;&lt;/p&gt;
&lt;p&gt;或者下面这个：&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="351px" data-flex-grow="146" height="737" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://xiaobox.github.io/p/2022-05-20-mysql-b-shu-ye-zi-jie-dian-shi-yong-dan-xiang-lian-biao-jin/003-09674de7.jpg" width="1080"&gt;&lt;/p&gt;
&lt;p&gt;希望能够帮到一直对B+tree 有误解的同学。&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="328px" data-flex-grow="137" height="788" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://xiaobox.github.io/p/2022-05-20-mysql-b-shu-ye-zi-jie-dian-shi-yong-dan-xiang-lian-biao-jin/004-ec6e6036.jpg" width="1080"&gt;&lt;/p&gt;</description></item><item><title>Redis 内存回收策略</title><link>https://xiaobox.github.io/p/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/</link><pubDate>Thu, 21 Apr 2022 08:22:02 +0000</pubDate><guid>https://xiaobox.github.io/p/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/cover.jpg" alt="Featured image of post Redis 内存回收策略" /&gt;&lt;p&gt;Redis的内存回收机制主要体现在以下两个方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;删除到达过期时间的键对象。&lt;/li&gt;
&lt;li&gt;内存使用达到&lt;code&gt;maxmemory&lt;/code&gt;上限时触发内存溢出控制策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="过期删除策略"&gt;&lt;a href="#%e8%bf%87%e6%9c%9f%e5%88%a0%e9%99%a4%e7%ad%96%e7%95%a5" class="header-anchor"&gt;&lt;/a&gt;过期删除策略
&lt;/h2&gt;&lt;p&gt;删除策略的目标：在内存占用与CPU占用之间寻找一种平衡，顾此失彼都会造成整体redis性能的下降，甚至引发服务器宕机或
内存泄露。&lt;/p&gt;
&lt;h3 id="设置redis键过期时间"&gt;&lt;a href="#%e8%ae%be%e7%bd%aeredis%e9%94%ae%e8%bf%87%e6%9c%9f%e6%97%b6%e9%97%b4" class="header-anchor"&gt;&lt;/a&gt;设置Redis键过期时间
&lt;/h3&gt;&lt;p&gt;先回顾一下Redis 提供的设置过期时间的命令：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EXPIRE：表示将键 key 的生存时间设置为 ttl 秒。&lt;/li&gt;
&lt;li&gt;PEXPIRE：表示将键 key 的生存时间设置为 ttl 毫秒。&lt;/li&gt;
&lt;li&gt;EXPIREAT：表示将键 key 的生存时间设置为 timestamp 所指定的秒数时间戳。&lt;/li&gt;
&lt;li&gt;PEXPIREAT：表示将键 key 的生存时间设置为 timestamp 所指定的毫秒数时间戳。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在Redis内部实现中，前面三个设置过期时间的命令最后都会转换成最后一个PEXPIREAT 命令来完成。&lt;/p&gt;
&lt;p&gt;其他相关命令还有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;移除键的过期时间 PERSIST：表示将key的过期时间移除。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;返回键的剩余生存时间&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TTL：以秒的单位返回键 key 的剩余生存时间。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PTTL：以毫秒的单位返回键 key 的剩余生存时间。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在Redis内部，每当我们设置一个键的过期时间时，Redis就会将该键带上过期时间存放到一个过期字典中。当我们查询一个键时，Redis便首先检查该键是否存在过期字典中，如果存在，那就获取其过期时间。然后将过期时间和当前系统时间进行比对，比系统时间大，那就没有过期；反之判定该键过期。&lt;/p&gt;
&lt;p&gt;此外：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对于字符串类型键，执行set命令会去掉过期时间，这个问题很容易在开发中被忽视&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如下是Redis源码中，set命令的函数setKey，可以看到最后执行了&lt;code&gt;removeExpire（db，key）&lt;/code&gt;函数去掉了过期时间：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;void&lt;/span&gt; &lt;span class="n"&gt;setKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redisDb&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;robj&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;robj&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lookupKeyWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dbAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dbOverwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;incrRefCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="err"&gt;去掉过期时间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;removeExpire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;signalModifiedKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&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;ul&gt;
&lt;li&gt;Redis不支持二级数据结构（例如哈希、列表）内部元素的过期功能，例如不能对列表类型的一个元素做过期时间设置。&lt;/li&gt;
&lt;li&gt;setex命令作为set+expire的组合，不但是原子执行，同时减少了一次网络通讯的时间。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="过期删除策略-1"&gt;&lt;a href="#%e8%bf%87%e6%9c%9f%e5%88%a0%e9%99%a4%e7%ad%96%e7%95%a5-1" class="header-anchor"&gt;&lt;/a&gt;过期删除策略
&lt;/h3&gt;&lt;p&gt;通常删除某个key，我们有如下三种方式进行处理&lt;/p&gt;
&lt;p&gt;1 定时删除&lt;/p&gt;
&lt;p&gt;在设置某个key 的过期时间同时，我们创建一个定时器，让定时器在该过期时间到来时，立即执行对其进行删除的操作。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/001-fc6a0ae5.jpg"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：定时删除对内存是最友好的，能够保存内存的key一旦过期就能立即从内存中删除。&lt;/li&gt;
&lt;li&gt;缺点：对CPU最不友好，在过期键比较多的时候，删除过期键会占用一部分 CPU 时间，对服务器的响应时间和吞吐量造成影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2 惰性删除（Lazy delete）&lt;/p&gt;
&lt;p&gt;设置该key 过期时间后，我们不去管它，当需要该key时，我们在检查其是否过期，如果过期，我们就删掉它，反之返回该key。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：对 CPU友好，我们只会在使用该键时才会进行过期检查，对于很多用不到的key不用浪费时间进行过期检查。&lt;/li&gt;
&lt;li&gt;缺点：对内存不友好，如果一个键已经过期，但是一直没有使用，那么该键就会一直存在内存中，如果数据库中有很多这种使用不到的过期键，这些键便永远不会被删除，内存永远不会释放。从而造成内存泄漏。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;3 定期删除&lt;/p&gt;
&lt;p&gt;每隔一段时间，我们就对一些key进行检查，删除里面过期的key。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;优点：可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除，也能有效释放过期键占用的内存。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缺点：难以确定删除操作执行的时长和频率。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果执行的太频繁，定期删除策略变得和定时删除策略一样，对CPU不友好。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果执行的太少，那又和惰性删除一样了，过期键占用的内存不会及时得到释放。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;另外最重要的是，在获取某个键时，如果某个键的过期时间已经到了，但是还没执行定期删除，那么就会返回这个键的值，这是业务不能忍受的错误&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="redis-使用的过期删除策略"&gt;&lt;a href="#redis-%e4%bd%bf%e7%94%a8%e7%9a%84%e8%bf%87%e6%9c%9f%e5%88%a0%e9%99%a4%e7%ad%96%e7%95%a5" class="header-anchor"&gt;&lt;/a&gt;Redis 使用的过期删除策略
&lt;/h3&gt;&lt;p&gt;Redis所有的键都可以设置过期属性，内部保存在过期字典中。由于进程内保存大量的键，维护每个键精准的过期删除机制会导致消耗大量的CPU，对于单线程的Redis来说成本过高，因此Redis采用惰性删除和定时任务删除机制实现过期键的内存回收。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/002-75f0543a.jpg"&gt;&lt;/p&gt;
&lt;p&gt;惰性删除：Redis的惰性删除策略由 &lt;code&gt;db.c/expireIfNeeded&lt;/code&gt; 函数实现，所有键读写命令执行之前都会调用 &lt;code&gt;expireIfNeeded&lt;/code&gt; 函数对其进行检查，如果过期，则删除该键，然后执行键不存在的操作；未过期则不作操作，继续执行原有的命令。&lt;/p&gt;
&lt;p&gt;定期删除：由&lt;code&gt;redis.c/activeExpireCycle&lt;/code&gt; 函数实现，函数以一定的频率运行，每次运行时，都从一定数量的数据库中取出一定数量的随机键进行检查，并删除其中的过期键。注意：并不是一次运行就检查所有的库，所有的键，而是随机检查一定数量的键。&lt;/p&gt;
&lt;p&gt;定期删除函数的运行频率，在Redis2.6版本中，规定每秒运行10次，大概100ms运行一次。在Redis2.8版本后，可以通过修改配置文件redis.conf 的 hz 选项来调整这个次数。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/003-bbf80080.jpg"&gt;&lt;/p&gt;
&lt;p&gt;看上面对这个参数的解释，建议不要将这个值设置超过 100，否则会对CPU造成比较大的压力。&lt;/p&gt;
&lt;p&gt;定时任务中删除过期键逻辑采用了自适应算法，根据键的过期比例、使用快慢两种速率模式回收键，流程如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/004-38ad1fc6.jpg"&gt;&lt;/p&gt;
&lt;h2 id="内存淘汰策略-逐出算法"&gt;&lt;a href="#%e5%86%85%e5%ad%98%e6%b7%98%e6%b1%b0%e7%ad%96%e7%95%a5-%e9%80%90%e5%87%ba%e7%ae%97%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;内存淘汰策略 （逐出算法）
&lt;/h2&gt;&lt;p&gt;当Redis所用内存达到&lt;code&gt;maxmemory&lt;/code&gt;上限时会触发相应的溢出控制策略。&lt;/p&gt;
&lt;p&gt;具体策略受&lt;code&gt;maxmemory-policy&lt;/code&gt;参数控制，Redis支持8种策略（有关LFU算法的，是从Redis4.0以后版本才有）：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/005-f166f98c.jpg"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;noeviction：默认策略，不会删除任何数据，拒绝所有写入操作并返回客户端错误信息（error）OOM command not allowed when used memory，此时Redis只响应读操作。生产一般不会选用&lt;/li&gt;
&lt;li&gt;allkeys-lru 利用LRU算法移除任何key （不管数据有没有设置超时属性，直到腾出足够空间为止）。&lt;/li&gt;
&lt;li&gt;allkeys-lfu 利用LRU算法移除任何key （不管数据有没有设置超时属性，直到腾出足够空间为止）&lt;/li&gt;
&lt;li&gt;volatile-lru：根据LRU算法删除设置了超时属性（expire）的键，直到腾出足够空间为止。如果没有可删除的键对象，回退到noeviction策略。&lt;/li&gt;
&lt;li&gt;volatile-lfu:根据LFU算法删除设置了超时属性（expire）的键，直到腾出足够空间为止。如果没有可删除的键对象，回退到noeviction策略。&lt;/li&gt;
&lt;li&gt;allkeys-random 无差别的随机移除，直到腾出足够空间为止。&lt;/li&gt;
&lt;li&gt;volatile-random：随机删除过期键，直到腾出足够空间为止。&lt;/li&gt;
&lt;li&gt;volatile-ttl：根据键值对象的ttl属性，删除最近将要过期数据。如果没有，回退到noeviction策略。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在redis.conf 配置文件中，可以设置淘汰方式：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/006-1577d384.jpg"&gt;&lt;/p&gt;
&lt;p&gt;内存溢出控制策略可以采用&lt;code&gt;config set maxmemory-policy{policy}&lt;/code&gt;动态配置。Redis支持丰富的内存溢出应对策略，可以根据实际需求灵活定制，比如当设置volatile-lru策略时，保证具有过期属性的键可以根据LRU剔除，而未设置超时的键可以永久保留。还可以采用allkeys-lru策略把Redis变为纯缓存服务器使用。当Redis因为内存溢出删除键时，可以通过执行&lt;code&gt;info stats&lt;/code&gt;命令查看evicted_keys指标找出当前Redis服务器已剔除的键数量。&lt;/p&gt;
&lt;h3 id="lfu"&gt;&lt;a href="#lfu" class="header-anchor"&gt;&lt;/a&gt;LFU
&lt;/h3&gt;&lt;p&gt;LFU 算法（Least Frequently Used，最不经常使用）：淘汰最近一段时间被访问次数最少的数据，以次数作为参考。&lt;/p&gt;
&lt;p&gt;需要指出的是 ：LRU 算法或者 TTL 算法都是不是很精确算法，而是一个近似的算法。Redis 不会通过对全部的键值对进行比较来确定最精确的时间值，从而确定删除哪个键值对 ， 因为这将消耗太多的时间 ， 导致回收垃圾执行的时间太长 ， 造成服务停顿。&lt;/p&gt;
&lt;p&gt;当存在热点数据时，LRU的效率很好，但偶发性的、周期性的批量操作会导致LRU命中率急剧下降，缓存污染情况比较严重。这时使用LFU可能更好点&lt;/p&gt;
&lt;h3 id="lru"&gt;&lt;a href="#lru" class="header-anchor"&gt;&lt;/a&gt;LRU
&lt;/h3&gt;&lt;p&gt;LRU算法， 最近最久未使用算法， Least Recently Used&lt;/p&gt;
&lt;p&gt;下图是一个淘汰的流程：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/007-500c2708.jpg"&gt;&lt;/p&gt;
&lt;p&gt;在Redis中LRU算法是一个近似算法，默认情况下，Redis随机挑选5个键，并且从中选取一个最近最久未使用的key进行淘汰，在配置文件中可以通过&lt;code&gt;maxmemory-samples&lt;/code&gt;的值来设置redis需要检查key的个数,但是检查的越多，耗费的时间也就越久,但是结构越精确(也就是Redis从内存中淘汰的对象未使用的时间也就越久~),设置多少，综合权衡吧~~~&lt;/p&gt;
&lt;p&gt;Redis 3.0对这个近似算法的优化&lt;/p&gt;
&lt;p&gt;新算法会维护一个候选池（大小为16），池中的数据根据访问时间进行排序，第一次随机选取的key都会放入池中，随后每次随机选取的key只有在访问时间小于池中最小的时间才会放入池中，直到候选池被放满。当放满后，如果有新的key需要放入，则将池中最后访问时间最大（最近被访问）的移除。当需要淘汰时，需要从池中捞出最久没被访问的key淘汰掉就行了。&lt;/p&gt;
&lt;p&gt;新旧算法的对比&lt;/p&gt;
&lt;p&gt;下面的图片是Redis官方文档给出的新旧算法对比结果：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2022-04-21-redis-nei-cun-hui-shou-ce-l-e/008-79bc5d44.jpg"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;浅灰色是被淘汰的数据&lt;/li&gt;
&lt;li&gt;灰色是没有被淘汰掉的老数据&lt;/li&gt;
&lt;li&gt;绿色是新加入的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以看到3.0的效果明显比2.8的要得多，并且取样数越大，越接近标准的LRU算法&lt;/p&gt;
&lt;p&gt;为什么Redis不使用真正的LRU ?&lt;/p&gt;
&lt;p&gt;原因很简单，理论的LRU需要你占用更大的内存(每个key还需要保存前后key的地址), 但你从上图就可以看出Redis 3.0使用的近似LRU算法使用起来的效果几乎与理论的LRU等效了。&lt;/p&gt;
&lt;p&gt;java实现LRU ？&lt;/p&gt;
&lt;p&gt;Java自带的集合框架非常强大，实现LRU算法可以直接使用LinkedHashMap集合框架，简单实现的话，只需要重写 &lt;code&gt;removeEldestEntry&lt;/code&gt; 方法即可。&lt;/p&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="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.LinkedHashMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.Map.Entry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LRUCache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedHashMap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;serialVersionUID&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;1L&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;accessCount&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hitCount&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;LRUCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;1f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;capacity&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;capacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;accessCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;containsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hitCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;19&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;20&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&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;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;21&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;22&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;23&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;24&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;containsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;25&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;accessCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;26&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;containsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;27&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hitCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;28&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;29&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;30&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;31&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;32&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;33&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;34&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;protected&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;removeEldestEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eldest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;35&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&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="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;36&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;37&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;38&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getAccessCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;39&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;accessCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;40&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;41&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;42&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getHitCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;43&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hitCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;44&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;45&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是LinkedHashMap的一个构造函数，传入的第三个参数accessOrder为true的时候，就按访问顺序对LinkedHashMap排序，为false的时候就按插入顺序，默认是为false的。当把accessOrder设置为true后，就可以将最近访问的元素置于最前面。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;public&lt;/span&gt; &lt;span class="n"&gt;LinkedHashMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ne"&gt;int&lt;/span&gt; &lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="ne"&gt;float&lt;/span&gt; &lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;accessOrder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accessOrder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accessOrder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&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;p&gt;这是LinkedHashMap中另外一个方法，当返回true的时候，就会remove其中最久的元素，可以通过重写这个方法来控制缓存元素的删除，当缓存满了后，就可以通过返回true删除最久未被使用的元素，达到LRU的要求。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;protected boolean removeEldestEntry(Map.Entry&amp;lt;K,V&amp;gt; eldest) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; return false;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="参考"&gt;&lt;a href="#%e5%8f%82%e8%80%83" class="header-anchor"&gt;&lt;/a&gt;参考
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;《Redis 开发与运维》&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://antirez.com/news/109" target="_blank" rel="noopener"
 &gt;http://antirez.com/news/109&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://redis.io/docs/manual/eviction/" target="_blank" rel="noopener"
 &gt;https://redis.io/docs/manual/eviction/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://zhuanlan.zhihu.com/p/149528273" target="_blank" rel="noopener"
 &gt;https://zhuanlan.zhihu.com/p/149528273&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.51cto.com/u" target="_blank" rel="noopener"
 &gt;https://blog.51cto.com/u&lt;/a&gt;_15239532/2835914&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.geekxh.com/1.99" target="_blank" rel="noopener"
 &gt;https://www.geekxh.com/1.99&lt;/a&gt;.其他补充题目/11.htm&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.cnblogs.com/ysocean/p/12422635.html" target="_blank" rel="noopener"
 &gt;https://www.cnblogs.com/ysocean/p/12422635.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.csdn.net/weixin" target="_blank" rel="noopener"
 &gt;https://blog.csdn.net/weixin&lt;/a&gt;_43230682/article/details/107670911&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>