吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 845|回复: 3
收起左侧

[分享] 爬虫er-从采集角度浅聊数据库

  [复制链接]
gfy1129 发表于 2026-6-15 16:41
本帖最后由 gfy1129 于 2026-6-15 17:02 编辑

今天不聊逆向,聊点数据库

关键字:数据库、mysql、优化、爬虫、采集
bg:26应届生入职某司-采集组一周,因为之前对数据库的主要应用是写一写增删改查的sql把爬下来的数据入库,最多处理一些并发控制加一些锁,对数据库稍微深入一点的,比如优化、引擎的选择、锁、分区等诸多应用欠佳,有的甚至都没了解过。
此贴主要记录这一周来自己的学习,趁着周末做一个归纳(碎碎念)。浅聊的范围都是围绕采集作业的应用所展开的,可能确实有点浅,大佬们当作看一个小白的学习历程吧哈哈,如果以下有什么理解偏差/错误,欢迎各位大佬斧正。随着后续的不断接触,此贴会不断的进行更新


这周的学习主要是围绕《Mysql8》的”10-18,20,25-28”这些章节展开的。


我让gpt大致总结了这些章节的摘要以及我已经涉及到的知识。




目前的章节
一、数据库引擎的选择
二、插入语句的优选
三、索引的空间和时间(InnoDB)
四、INFORMATION_SCHEMA
五、关于 MySQL 中锁的浅谈
六、事务、隔离级别、MVCC、redo / undo 浅谈
七、分区


以下的学习基本上都是围绕,“这是什么”,“有什么用”,“解决了什么问题”,“在采集作业中的应用场景是什么”



一、数据库引擎的选择
注:这里只了解了mysql的三种引擎innodb,myisam,tokudb以及clickhousey引擎.
(1)存储引擎是什么:
  MySQL 负责“听懂 SQL”,存储引擎负责“怎么把数据真正存到磁盘、怎么加锁、怎么建索引、怎么恢复、怎么并发读写”,不同引擎的选取,相应的数据处理的时间、空间不同。
(2)数据入库时,较好的引擎选型可以
较好的引擎选型 = 更高的写入速度 + 更低的存储成本 + 更少的锁等待 + 更安全的崩溃恢复
(3)解决的问题:
减少:①写入卡死 ②磁盘成本失控 ③查询查重缓慢 ④死锁与并发冲突 等等
4)对以上四种引擎进行DML/DDL实验耗时测试:
测试bg:建同样的表,use不同的引擎,相同的10w条电商数据;
  测试项目:DML语句的测试(1k条数据),DDL语句的测试(冷测试以及模拟并发下的热测试),每个测试项目三轮-取平均值。控制变量,仅引擎不同,其他均相同
测试结果:

(5)补充以上引擎的压缩比对比
测试结果:

(6)测试结果分析


应用场景推荐引擎 / 数据库为什么
URL 任务队列InnoDB高频 UPDATE,需要事务和行级锁
URL 去重表InnoDB需要唯一索引、防止重复采集
商品当前详情表InnoDB需要 UPSERT、更新当前价格、状态准确
文章当前详情表InnoDB需要按 URL/hash 去重和更新
采集失败重试表InnoDBretry_count、status 经常变化
代理池状态表InnoDBIP 状态、失败次数、冷却时间频繁更新
网站规则表InnoDB / MyISAM读多写少,小表;实际建议统一 InnoDB
采集日志表ClickHouse大量追加写入,后续 COUNT/GROUP BY
请求耗时表ClickHouse适合时间范围统计、平均耗时分析
状态码分布表ClickHouse适合聚合统计
商品价格历史表ClickHouse历史明细多,适合趋势分析
评论历史表ClickHouse大量追加,适合后续分析
长期归档数据ClickHouse / 冷存储压缩率好,适合保留历史
写密集旧系统TokuDB只适合历史项目理解,新项目不推荐
只读小字典表MyISAM 可用但生产中一般继续用 InnoDB 更省心

  在我看来,我的理解就是,主业务表即DML比较多的比如:任务表、商品详情表之类的优先Innodb;而大部分只需要追写数据/大数据量/后续需要分析优先clickhouse。另外两种引擎在我看来没有明显优势。
并且clickhouse的压缩比很大,大数据量压缩较优(如上表的测试数据,7.435mb/19.326mb),只有原数据大小的38.5%,而inndb膨胀至原数据大小的210%,
主要还是因为clickhouse是列级存储,innodb是行级存储且二级索引的空间开销较大且需要支持ACID,都需要留出额外的空间。




二、插入语句的优选
(1)插入语句的耗时也有差异(不考虑LOAD语句)
以下为四种常用的插入语句
①单条insert + 自动提交
[SQL] 纯文本查看 复制代码
-- 最慢方式:每行一条 INSERT,每条自动提交
SET autocommit = 1;

FOR row IN 待插入数据:

INSERT INTO target_table(col1, col2, col3, ...)
VALUES (...);

-- 每条 INSERT 执行完,MySQL 自动提交一次

END FOR

  ②单条insert + 显式事务
[SQL] 纯文本查看 复制代码
-- 单条 INSERT,但是使用显式事务
SET autocommit = 0;

row_count_in_transaction = 0

FOR row IN 待插入数据:

INSERT INTO target_table(col1, col2, col3, ...)
VALUES (...);

row_count_in_transaction = row_count_in_transaction + 1

IF row_count_in_transaction == 50 THEN
COMMIT;
row_count_in_transaction = 0
END IF

END FOR

COMMIT;

SET autocommit = 1;

③多值 insert + 无显式事务
[SQL] 纯文本查看 复制代码
-- 多值 INSERT,但是 autocommit = 1

SET autocommit = 1;

batch_values = []

FOR row IN 待插入数据:

把 row 加入 batch_values

IF batch_values 数量 == 50 THEN

INSERT INTO target_table(col1, col2, col3, ...)
VALUES
(...),
(...),
(...),
-- 一共 50 行
(...);

-- autocommit = 1,所以这条 INSERT 执行完自动提交

清空 batch_values

END IF

END FOR

IF batch_values 不为空 THEN
INSERT INTO target_table(col1, col2, col3, ...)
VALUES
(...),
(...);
END IF

④ 事务  + 多值insert
[SQL] 纯文本查看 复制代码
-- 推荐方式:事务 + 多值 INSERT

SET autocommit = 0;

batch_values = []
sql_count_in_transaction = 0

FOR row IN 待插入数据:

把 row 加入 batch_values

IF batch_values 数量 == 50 THEN

INSERT INTO target_table(col1, col2, col3, ...)
VALUES
(...),
(...),
(...),
-- 一共 50 行
(...);

清空 batch_values

sql_count_in_transaction = sql_count_in_transaction + 1

IF sql_count_in_transaction == 20 THEN
COMMIT;
sql_count_in_transaction = 0
END IF

END IF

END FOR

-- 处理最后不足 50 行的数据
IF batch_values 不为空 THEN
INSERT INTO target_table(col1, col2, col3, ...)
VALUES
(...),
(...);
END IF

COMMIT;

SET autocommit = 1;


(2)模拟插入10w行数据,模拟每个响应列表50条数据,插入对比耗时
测试结果:


(3)结果分析
  显而易见、毫无疑问,事务+insert多值插入耗时最少,性能最优,不过多赘述





三、索引的空间和时间
注:这个主题的浅谈只聊innodb引擎
碎碎念:索引能加快select的速度,这个是之前知道的,但是问什么能加快速度呢,加快了多少呢,索引只有好处吗,坏处是什么。
我将带着我刚开始的疑问,开始以下的实验和理论学习

(1)索引是什么?
一本书,通常都有目录,想快速查阅某一个章节的时候,通常只需要翻阅目录,看一看目标章节对应的页码,翻到即可。同样的,数据库就是一本巨大是书,要想快速select某个数据,需要给这个列名加上“索引”,即把对应的章节的页码“写”在目录中,代价就是,增加了一些额外的空间,即空间换时间。
(2)索引加快了多少,这与怎么加索引息息相关
实验:相同10W条数据,select同样的数据行,变量:索引方式不同,测试耗时
  ① 无普通索引,仅主键
  ② 单列索引
  ③ 组合索引(合适的组合索引顺序)
  ④ 组合索引(不合适的索引顺序)
  ⑤ 覆盖索引
测试结果:

测试结果分析:
如果不加索引,select则是对数据库中的全表进行扫描,速度非常慢。若加了索引,则是在索引树(B+TREE)中快速查找;
如果加了索引,则加索引的每一个都比不加索引的要快的多。但是他们之间也有差异。
  对比实验3和实验4,同样是组合索引,仅仅两个索引字段的顺序不同,耗时缺差了十几倍,为什么呢?
因为这个执行的查询语句是类似(下边代码块),数据库先确定“sku_id =?”这个列的值,然后在对应值中取“created_at ”的范围,故联合索引,需要先确定的字段排在前边,后确定的字段排在后边是比较优的写法,相应的耗时就比较小。
[SQL] 纯文本查看 复制代码
WHERE sku_id = ?
AND created_at BETWEEN ? AND ?;

   实验5 什么是覆盖索引,为什么覆盖索引耗时是这样子
覆盖索引就是,把查询涉及的所有字段(不止过滤条件where后的字段,包括select的字段)都加上所有-全覆盖。读数据时,mysql只需要在索引中读取结果即可,不需要再进行回表读数据。理论上这覆盖索引是比较快的,但是在此次实验中可能“覆盖索引的“减少回表收益”,小于它自身“索引变宽带来的额外成本”。”。覆盖索引固然快,但是带来一定的空间成本,但是空间浪费,需要再合适的情况下使用覆盖索引,比如select * 要查全字段,这时使用覆盖索引,所需索引的字段就很宽了,就远远不划算了。
  对比实验1(单列索引)和实验4(合适的组合索引),为什么合适的组合索引更快点
单列索引只能先按一个条件缩小范围;合适的组合索引可以把多个条件一起变成“索引定位条件”,扫描更少、回表更少,所以更快。但是差距不明显的原因是数量级10w不算很大,数量级大,这个合适的组合索引的优势就应该会体现出来了
总结:索引优化的重点不是“有没有索引”,而是“索引顺序、索引宽度、查询条件是否匹配”。对于 sku_id + created_at 查询,最优先推荐 (sku_id, created_at) 这种窄组合索引。
(3)这样看来,索引是越多越好吗
实验:相同 10W 条数据,表结构相同,存储引擎相同,变量为索引数量和索引宽度不同。观察索引数量递增后,表空间占用的变化。
  ① 仅主键索引
  ② 单列索引
  ③ 合适的组合索引
  ④ 单列索引 + 合适的组合索引
  ⑤ 多个业务索引
  ⑥ 宽覆盖索引

测试结果:

测试结果分析:
不用过多赘述,显而易见,索引越多,所占用空间是递增的。并不是索引越多越好。
(4)summary-index
  通过以上两个实验可以看出,索引本质上是一种“空间换时间”的优化手段。索引的收益是加快查询,成本是占用空间并增加增删改的维护开销。加上合适的索引很重要。




四、INFORMATION_SCHEMA

(1)INFORMATION_SCHEMA是什么 有什么用
  可以把它认为它是“数据库的说明目书”,INFORMATION_SCHEMA存放的是这些数据表的“说明信息”,
[Asm] 纯文本查看 复制代码
有哪些数据库?
每个数据库有哪些表?
每张表有多少行?
每张表占多少空间?
每张表有哪些字段?
字段类型是什么?
有哪些索引?
索引顺序是什么?
有没有分区?
有没有外键?
有没有触发器、视图、存储过程?

(2)INFORMATION_SCHEMA是mysql默认的数据库之一,而其他三个默认数据库是什么,有什么用
[Asm] 纯文本查看 复制代码
information_schema
mysql
performance_schema
sys
你的业务数据库...

这四个默认数据库的作用分别是什么


(3)INFORMATION_SCHEMA 和优化有什么关系?
  它不直接对数据库进行优化,但是它是优化前的“体检工具”。
[Asm] 纯文本查看 复制代码
表有多大?
索引有多大?
哪些字段类型不合理?
有哪些索引?
索引顺序是什么?
有没有冗余索引?
表是否分区?
表的字符集和排序规则是什么?
哪些表行数最多?
哪些表空间膨胀?


(4)举例常用的对数据库的体检语法。
[SQL] 纯文本查看 复制代码
SELECT
table_name,
column_name,
column_type
FROM information_schema.columns
WHERE table_schema = 'crawler_db'
AND data_type IN ('text', 'mediumtext', 'longtext', 'varchar')
ORDER BY table_name;

输出:


(5)summary
它不是直接优化 SQL 的工具,而是 MySQL 的“数据库元数据查询系统”。它能告诉你数据库里有什么、表结构是什么、字段是什么、索引怎么建、表占多少空间、分区怎么分。数据库优化之前,先用它做体检。
在实际优化数据库中,可以采用一下的排查顺序
[Asm] 纯文本查看 复制代码
先查大表;
再查索引空间;
再查索引顺序;
再查字段类型;
再查主键和唯一约束;
最后结合 EXPLAIN、慢查询日志、Performance Schema / sys 库判断具体 SQL 怎么优化。





五、关于mysql中锁的浅谈
从一些基础的概念说起
(1)锁是什么 有什么用 解决了什么问题
  在我看来,锁就是一个数据的“监督员”,特别是在人多(并发数大)对数据进行一些操作时,比如两个人同时修改同一条url任务时,如果没有数据的监督员(锁),就可能出现状态混乱:一个线程刚把任务标记为“抓取中”,另一个线程又把它改成“已完成”或者“失败”。为了保证数据一致性,数据库必须让这两个修改操作有先后顺序,即监督这些人(并发处理)能够安全的协作,而不出现混乱。锁不是为了阻止大家操作,而是为了让并发操作按规则排队,避免互相覆盖。
为什么爬虫采集作业中更可能用到锁
[Asm] 纯文本查看 复制代码
爬虫采集系统有几个特点:
多个线程或多个进程同时跑;
大量 INSERT;
大量 UPDATE 任务状态;
大量 ON DUPLICATE KEY UPDATE;
URL 去重表、任务队列表、商品详情表经常被并发访问;
某些失败任务还会反复重试。

锁可以解决的问题可以概括为:
[Asm] 纯文本查看 复制代码
防止同一份数据被多个事务同时乱改;
防止任务状态、商品价格、URL 去重等数据出现并发混乱;
保证一个事务在执行过程中,关键数据不会被其他事务随意修改;
避免多个爬虫线程同时抢到同一条任务;
保证并发写入时数据结果是可控、可信、一致的。


(2)mysql中常用的锁
①共享锁 S LOCK
大白话:我正在读,你也可以读,但你不能改
共享锁之间一般是兼容的,也就是多个事务可以同时对同一行加共享锁
[SQL] 纯文本查看 复制代码
SELECT *
FROM crawl_url_queue
WHERE id = 1001
FOR SHARE;


②排他锁X LOCK
大白话“我要改这行,别人不能同时改,也不能加共享锁读
第一种写法就是普通的update语句,一个 UPDATE 语句本身就是原子操作,自动加排他锁
[SQL] 纯文本查看 复制代码
UPDATE crawl_url_queue
SET status = 1
WHERE id = 1001;


第二种写法,读并锁定-先读后改
[SQL] 纯文本查看 复制代码
START TRANSACTION;
SELECT status FROM crawl_url_queue WHERE id = 1001 FOR UPDATE;
-- 应用层判断 status=0
UPDATE crawl_url_queue SET status = 1 WHERE id = 1001;
COMMIT;

这种的应用场景是,你需要根据当前行的状态来决定是否更新,并且这个“判断-执行”操作必须是原子的。

③意向锁IS / IX (无感表级锁)
意向锁是表级锁,但它不是用来真正锁住整张表的,而是用来告诉数据库:我接下来准备在这张表的某些行上加共享锁或排他锁。事务准备对某些行加共享锁时,表上会有 IS 锁;
事务准备对某些行加排他锁时,表上会有 IX 锁。
为什么有意向锁,解决了什么问题:
[Asm] 纯文本查看 复制代码
假设没有意向锁。现在事务 A 修改了第 100 行,也就是在第 100 行上持有一个排他锁 (X)。
这时,事务 B 想要干一件大事,比如执行 ALTER TABLE 或 LOCK TABLES ... WRITE,它需要给整张表加一个排他锁 (X)。
数据库怎么判断能不能加这个表锁?它必须确认:这张表里现在没有其他事务持有任何一行的排他锁。
在没有意向锁的情况下,数据库只有一个笨办法:从头到尾遍历这张表的所有行,检查每一行是否有锁。 对于一张有千万行数据的爬虫任务表,这个检查过程本身就会造成巨大的性能灾难,完全不可行。

有了意向锁,事情就简单了:
事务 A 在修改第 100 行时,会自动在表级别留下一个标记,叫意向排他锁 (IX)。意思是:“注意,本事务打算或正在某些行上持有排他锁。”
事务 B 想加表级排他锁时,只需要看一眼表上有没有冲突的意向锁,它发现表上已经有了 IX 锁,就知道表里有行被锁住了,于是直接等待,无需检查任何一行
用极小的代价,把一个 O(n) 的行扫描判断,变成了 O(1) 的表级标志位判断,让表锁和行锁能够高效共存。

④ 记录锁(无感行级锁)
大白话“有线程对数据操作时 → 先检索行对应的索引 → 记录锁对对应行的索引加锁 → 表示数据正在被操作 → 其他线程等待”,记录锁就是操作前在索引上做的“占用标记”,用来保证并发修改的有序性。
⑤ 间隙锁
大白话“比如 where id>= 3,id<=5(存在记录id=3 和id=5),记录锁锁的是id=3,5这两条存在的数据记录,而间隙锁锁住的是3和5之间不存在的id=4这个记录,这行数据虽然还不存在,但这个位置我先占了,谁也别想在我提交之前往这儿插新数据,解决了幻读的问题”,只防插入,不防修改。
⑥ 临键锁
大白话“这一行我锁了,它前面的空档我也锁了,想改这行不行,想往它前面插新数据也不行。”,既防改,又防插。

对比以上三种锁


(3锁与索引的关系
  所有行级锁(记录锁、间隙锁、临键锁)都是加在索引记录上的。索引设计直接决定了锁的粒度和并发性能。SQL 走了索引,锁就是精准的行级锁;没走索引,行锁退化为表锁,并发崩溃。
(4)summary-lock


六、事务、隔离级别、MVCC、redo/undo 浅谈
(1)事务是什么?有什么用?解决了什么问题?
在我看来,事务就是把多条sql打包为一个“整体动作”,这个动作要么全部成功,要么全部失败。
  事务的作用就是保证这些相关操作是一个整体,比如,银行系统,A->B,100元。①A-100元 ②B+100元 执行顺序是①②,如果执行①时,出错了,②不知道,继续执行了,这不就乱套了。所以把①和②打包为一个整体(事务),①出错时,可以进行回滚,这个动作要么全部成功,要么全部失败。
  典型写法:
[SQL] 纯文本查看 复制代码
START TRANSACTION;

SELECT id, url
FROM crawl_task
WHERE status = 0
ORDER BY updated_at
LIMIT 1
FOR UPDATE;

UPDATE crawl_task
SET status = 1,
updated_at = NOW()
WHERE id = 上一步查到的id;

COMMIT;

(2)提到事务就会想起来ACID。事务、ACID和锁有什么关系?
事务是让一组操作遵守 ACID 的容器,而锁、undo log、redo log、MVCC 是 InnoDB 用来实现 ACID 的四件套工具。
(3)ACID

①原子性 Atomicity
  大白话“一个事务里的 SQL,要么都成功,要么都失败。
②一致性 Consistency
  大白话“事务执行前后,数据都应该处于合理状态。
  
[Asm] 纯文本查看 复制代码
比如任务状态只能是:0:待抓取
1:抓取中
2:成功
3:失败
事务不能把任务状态改成一个业务上不存在的值,比如 999。
隔离性 Isolation
  大白话“多个事务同时执行时,彼此之间不能乱影响。
④持久性 Durability
大白话“事务一旦 COMMIT 成功,数据就应该尽量可靠地保存下来。”
(4)在采集作业中,为什么要用到事务。
  在这些场景下,会用到事务
[Asm] 纯文本查看 复制代码
抢任务;
更新任务状态;
写入采集结果;
URL 去重;
失败重试;
更新代理 IP 状态;
记录采集日志和任务状态变更。

  worker 领取任务时,应该尽量保证:
[Asm] 纯文本查看 复制代码
一个任务只被一个 worker 领取;
领取后状态立即变成抓取中;
失败后 retry_count 正确增加;
成功后结果入库,任务状态也同步更新。

  如果没有事务,就容易出现:
[Asm] 纯文本查看 复制代码
任务重复领取;
任务状态和结果表不一致;
失败次数被并发覆盖;
一个 worker 处理了一半异常退出;
数据库里留下半成品状态。

采集作业中,不是所有 SQL 都必须放进事务,但凡涉及“多个动作必须保持一致”的地方,就应该考虑事务。
(5)什么是隔离级别 解决了什么问题
  隔离级别就是,多个事务同时执行时,一个事务能看到另一个事务修改到什么程度。
  解决了三种并发的副作用:

(6)四种隔离级别分别是什么
①READ UNCOMMITTED,读未提交:“别人事务还没提交的数据,我也可能读到。”----> 这会产生脏读
READ COMMITTED,读已提交:“只能读到别人已经提交的数据。---->这会避免脏读,产生不可重复读
REPEATABLE READ,可重复读:“同一个事务里,多次普通 SELECT 看到的数据快照基本一致。这是innodb的默认等级,会减少很多并发读写带来的混乱。
SERIALIZABLE,串行化:“事务尽量一个一个排队执行,隔离最强,并发最差。这个隔离级别最严格,但性能代价也最大。

(7)MVCC是什么 有什么作用 解决了什么问题
MVCC(多版本并发控制)是 InnoDB 实现非阻塞读的核心机制。同一行数据,InnoDB 可能保存多个版本。普通 SELECT 查询时,不一定非要读最新正在被修改的版本,而是可以读一个对当前事务来说合理的历史版本。
区分普通select和加锁select

解决了什么问题?
MVCC 的核心价值:普通读尽量不阻塞写,写也尽量不阻塞普通读
(8)undo log和redo log 是什么 有什么用 解决了什么问题

(10)summary
这一块应该是纯理论,挺干巴,大概就是“事务保证一组 SQL 的整体正确性;锁保证并发修改不乱;MVCC 保证普通读尽量不阻塞写;undo log 保证能回滚和读旧版本;redo log 保证数据库崩溃后能恢复已提交的修改。对于爬虫采集系统来说,事务不是越大越好,而是越短、越明确、越可控越好。”



七、分区
(1)分区是什么?有什么用?解决了什么问题?
  在我看来,分区就是把一张“大表”按照某个规则,在数据库内部拆成多个“小区域”,但是从使用者角度看,它仍然是一张表。相当于,图书馆中,按照不同的类目,把书放在不同的书架上,方便统一管理。
解决的问题?分区最主要解决的不是“所有查询都变快”,而是解决“大表越来越大之后,数据管理和范围查询变难”的问题。
有什么用?
[Asm] 纯文本查看 复制代码
让大表按规则拆成多个可管理的分区;
1. 查询带上分区字段时,可以只扫描相关分区;
2. 删除历史数据时,可以直接删除整个分区;
3. 方便按时间归档、清理、维护大表;
4. 减少某些大范围查询扫描的数据量;
5. 让持续增长的日志表、历史表更容易维护。

爬虫的应用场景
[Asm] 纯文本查看 复制代码
采集日志越来越大;
价格历史越来越大;
请求记录越来越大;
状态码统计越来越大;
每天都在追加数据;
老数据还要保留一段时间;
偶尔还要查某一天、某一周、某个月的数据。

表越来越大;
查询历史范围越来越慢;
删除老数据很慢;
DELETE 大量历史数据容易产生锁、undo、redo 压力;
索引维护成本越来越高;
备份和归档越来越麻烦。


分区就是为了解决这种“大表持续增长”的管理问题。
(2)分区是能快速的知道哪一部分是什么数据,这挺听起来更像是一种“粗且宽”的索引,它和索引有什么区别呢
  索引解决的是,在一堆数据里如何快速的定位行。
  分区解决的是,这堆数据能不能按规则分成几个大块,查询时只看其中几个快。

(3)分区类型及定义
①类型
[Asm] 纯文本查看 复制代码
[size=3]1. RANGE 分区:按范围分
2. RANGE COLUMNS 分区:按列值范围分,适合 DATE / DATETIME
3. LIST 分区:按固定值列表分
4. LIST COLUMNS 分区:按列值列表分
5. HASH 分区:按表达式哈希分
6. KEY 分区:MySQL 内部哈希分
7. 子分区:先分大区,再在每个大区里继续分小区[/size]

②定义
1. 定义的模板
[SQL] 纯文本查看 复制代码
CREATE TABLE 表名 (
字段定义,
主键定义,
索引定义
) ENGINE=InnoDB
PARTITION BY 分区方式(分区字段或表达式) (
PARTITION 分区名1 分区规则,
PARTITION 分区名2 分区规则,
PARTITION 分区名3 分区规则
);



2. 按范围分 range分区
分区键的形式:必须是一个整数表达式,如 YEAR(date)TO_DAYS(date) 或直接是整数列,表达式结果必须是整数,边界定义:VALUES LESS THAN (整数值)


[SQL] 纯文本查看 复制代码
CREATE TABLE log_by_year (
id BIGINT NOT NULL,
created_at DATETIME NOT NULL,
content VARCHAR(200),
PRIMARY KEY (id, created_at)
) ENGINE=InnoDB
PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p2026 VALUES LESS THAN (2027),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
即
YEAR(created_at) < 2025 进入 p2024
YEAR(created_at) < 2026 进入 p2025
YEAR(created_at) < 2027 进入 p2026
更大的值进入 pmax

3. 按列值范围分 RANGE COLUMNS 分区
分区键的形式:直接说过一个或多个列名,不需要包装为表达式。原生支持 int、data、datetime、char、varchar等多种类型。边界定义VALUES LESS THAN (值),值的类型须与列类型匹配,如日期、字符串


按照created_at 的时间范围分区。
[SQL] 纯文本查看 复制代码
CREATE TABLE crawl_log_range (
id BIGINT NOT NULL AUTO_INCREMENT,
domain VARCHAR(100) NOT NULL,
url_hash CHAR(32) NOT NULL,
status_code INT NOT NULL,
cost_ms INT NOT NULL,
created_at DATETIME NOT NULL,
PRIMARY KEY (id, created_at),
KEY idx_created_at(created_at),
KEY idx_domain_created(domain, created_at)
) ENGINE=InnoDB
PARTITION BY RANGE COLUMNS(created_at) (
PARTITION p202601 VALUES LESS THAN ('2026-02-01'),
PARTITION p202602 VALUES LESS THAN ('2026-03-01'),
PARTITION p202603 VALUES LESS THAN ('2026-04-01'),
PARTITION p202604 VALUES LESS THAN ('2026-05-01'),
PARTITION p202605 VALUES LESS THAN ('2026-06-01'),
PARTITION p202606 VALUES LESS THAN ('2026-07-01'),
PARTITION pmax VALUES LESS THAN (MAXVALUE)
);
其中
PARTITION p202606 VALUES LESS THAN ('2026-07-01')
表示
小于 '2026-07-01',并且不属于前面分区的数据,会进入 p202606。

区别

4. 按固定值列表分 :LIST 分区
[SQL] 纯文本查看 复制代码
CREATE TABLE crawl_source_log (
id BIGINT NOT NULL AUTO_INCREMENT,
source_id INT NOT NULL,
url_hash CHAR(32) NOT NULL,
status_code INT NOT NULL,
created_at DATETIME NOT NULL,
PRIMARY KEY (id, source_id),
KEY idx_source_created(source_id, created_at)
) ENGINE=InnoDB
PARTITION BY LIST (source_id) (
PARTITION p_jd VALUES IN (1),
PARTITION p_tmall VALUES IN (2),
PARTITION p_pdd VALUES IN (3),
PARTITION p_other VALUES IN (4,5,6,7,8,9)
);

source_id = 1 的数据进入 p_jd
source_id = 2 的数据进入 p_tmall
source_id = 3 的数据进入 p_pdd
source_id 在 4~9 的数据进入 p_other

5. 按列值列表分 LIST COLUMNS 分区
[SQL] 纯文本查看 复制代码
CREATE TABLE crawl_platform_log (
id BIGINT NOT NULL AUTO_INCREMENT,
platform VARCHAR(20) NOT NULL,
url_hash CHAR(32) NOT NULL,
created_at DATETIME NOT NULL,
PRIMARY KEY (id, platform)
) ENGINE=InnoDB
PARTITION BY LIST COLUMNS(platform) (
PARTITION p_ecommerce VALUES IN ('jd', 'tmall', 'pdd'),
PARTITION p_content VALUES IN ('zhihu', 'weibo', 'bilibili'),
PARTITION p_other VALUES IN ('other')
);

platform 是 jd、tmall、pdd,进入电商分区;
platform 是 zhihu、weibo、bilibili,进入内容平台分区。

区别:

还有HASH/key/子分区,采集涉及的应该较少,不再介绍
(4)注意的一个小点儿
mysql分区表有一个重要的限制:分区表达式中用到的字段,必须包含在表的每一个唯一键中,包括主键。
比如你按 created_at 分区:
[SQL] 纯文本查看 复制代码
PARTITION BY RANGE COLUMNS(created_at)

那么主键不能只写:
[SQL] 纯文本查看 复制代码
PRIMARY KEY (id)

通常要写成:
[SQL] 纯文本查看 复制代码
PRIMARY KEY (id, created_at)

如果有唯一键,也要包含 created_at:
[SQL] 纯文本查看 复制代码
UNIQUE KEY uk_url_hash_created(url_hash, created_at)

(5)分区的应用
① 增加新分区
[SQL] 纯文本查看 复制代码
ALTER TABLE crawl_log_range
ADD PARTITION (
PARTITION p202607 VALUES LESS THAN ('2026-08-01')
);



② 删除旧分区(直接删除整个分区的数据)
[SQL] 纯文本查看 复制代码
ALTER TABLE crawl_log_range DROP PARTITION p202601;

③ 清空分区(保留分区结构)
[SQL] 纯文本查看 复制代码
ALTER TABLE crawl_log_range TRUNCATE PARTITION p202601;

④ 显式指定分区更新和删除
[SQL] 纯文本查看 复制代码
UPDATE crawl_log_range PARTITION (p202606)
SET status_code = 500
WHERE url_hash = MD5('https://example.com/a');

[SQL] 纯文本查看 复制代码
DELETE FROM crawl_log_range PARTITION (p202606)
WHERE status_code = 404;

⑤ 查询:自动分区裁剪
[SQL] 纯文本查看 复制代码
EXPLAIN PARTITIONS
SELECT *
FROM crawl_log_range
WHERE created_at >= '2026-06-01'
AND created_at < '2026-07-01';

分区裁剪的核心思想就是:不要扫描不可能有匹配值的分区,WHERE 条件里要有分区字段
⑥ 插入数据:自动进入对应分区


(6)分区裁剪和索引查找的区别


一句话:分区裁剪:决定去哪些文件夹找。索引查找:在文件夹里通过目录找具体文件。


②上述分区裁剪和索引查找两种方式看似都是加快了检索速度,但是具体加快了多少呢?两个对比,以及怎么搭配是比较优的结果呢通过下边一个实验揭晓。
实验:相同 10W 条数据,表结构相同,存储引擎相同,变量为有无分区,索引。同样的select语句,统计各自的耗时和空间占用。

实验结果:


实验结果分析:分区裁剪:减少要扫描的分区,但会增加分区管理成本。
索引查找:减少分区内或表内扫描行数,但会增加二级索引空间。
分区 + 索引:查询能力最完整,统一管理能力最强,但空间占用最大。
分区和索引都是用空间、管理成本换查询效率;分区负责缩小“大范围”,索引负责定位“具体行”。在爬虫大日志表中,两者配合很有价值,但在小表或高频更新表中不能盲目使用。
(增加分区之后,空间占用增大的原因:每个分区都是独立的小表,“文件头、元数据页、数据页和索引页、碎片和预分配空间都会增加额外空间)


免费评分

参与人数 3吾爱币 +9 热心值 +3 收起 理由
music984 + 1 + 1 码字辛苦
涛之雨 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
Maiz1888 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

dxw13920 发表于 2026-6-17 09:31
虽然看不懂,但是这么多内容可定楼主是花了心思的,点赞。
loading2025 发表于 2026-6-17 10:19
miaomiao105 发表于 2026-6-17 17:43
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-10 19:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表