☰
古诗词库MySQL导入实战:字符集、全文索引与中文检索
2026/9/26 8:03:00 网站建设 项目流程

简介:古诗词库(中文简体)是一份收录中华古诗词的关系型数据库资源,面向传统文化研究者、教育工作者及诗词爱好者,可用于批量检索、分类整理与文本分析。压缩包共 318 个 SQL 文件,整体约 53.85MB,文件按数据表拆分为作者表、诗作表、词作表等模块,用户借助数据库客户端导入后,即可用标准结构化查询语句完成跨表查询与统计。数据内容方面,唐诗部分约收 5.5 万首,涵盖初唐到晚唐李白、杜甫、王之涣、白居易等名家代表作,绝句、律诗、古风等体裁均有涉及;宋词部分包含 1564 位作者、21050 首词作,苏轼的豪放、李清照的婉约、辛弃疾的壮志、柳永的深情皆可检索原文。除诗词正文外,部分诗词还附有注释与赏析,便于理解创作背景与艺术内涵。该资源发布以来已有 544 人浏览学习,适合搭建古诗词语料库、开展诗词风格分析,或用于课程教学与文化内容开发。

1. 古诗词库 MySQL:一份能直接导入检索的唐诗宋词语料,到底值不值得下

做中文内容产品的人,十有八九都经历过满地找古诗词数据的尴尬:网页上扒下来的 HTML 带一堆标签,Word 文档排版稀碎,PDF 转出来全是乱码,光清洗数据就能耗掉一两个晚上。这份《古诗词库(中文简体)-MySQL》解决的就是这个痛点——它直接把唐诗、宋词、作者信息做成了 9 个 MySQL 的 SQL 分片文件,导入就能查,不需要自己做表结构、不需要清洗字段,适合做国学内容 App、教育产品、语料分析或者只是想给个人项目补一个诗词检索功能的开发者。它的边界也很清楚:核心是数据,不附带前端界面,也不打包任何 API 服务,你要做的事是把它正确导进自己的数据库。下面我按自己拆库的习惯,从环境准备讲到导入执行,再讲坑和进阶用法。

2. 环境准备与表结构预判:先摸清字符集和文件底细再动手

拿到 SQL 文件第一反应就是source一把梭,这是最容易翻车的开场。SQL 文件导入的成败,一半在导入前就决定了。这一章先解决两个前置问题:用什么字符集导入、这些文件里到底装了什么。

2.1 字符集与排序规则:utf8mb4 是唯一解,别用 utf8

古诗词文件里全是中文简体,看起来跟编码关系不大,但这类资源在制作时往往没有统一声明字符集,如果你直接用默认配置导入,轻则注释乱码,重则整张表出现 "???"。MySQL 8.0 的默认字符集已经是 utf8mb4,但如果你还在跑 5.7 或者更老的版本,服务器端很有可能还是 latin1。

我一般会先在命令行确认两件事:一是当前连接的字符集,二是文件头部有没有 SET NAMES 声明。检查连接字符集的命令很简单:

SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'character_set_database'; SHOW VARIABLES LIKE 'collation_server';

逻辑说明:这三条语句分别查看服务器、数据库、排序规则的当前值。character_set_server是服务器端默认字符集,直接决定新建库表时的继承值;collation_server是排序规则,对中文场景建议用utf8mb4_general_ci或utf8mb4_unicode_ci,前者查询性能略优,后者对 Unicode 排序更精确,诗词搜索没有特殊排序需求,选哪个都行。

参数说明:如果查出来不是 utf8mb4,不用急着改全局配置,可以在导入前单独指定。我更推荐的做法是在建库时就把字符集钉死:

CREATE DATABASE IF NOT EXISTS gushici DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

逻辑说明:DEFAULT CHARACTER SET和COLLATE会写进库的系统表,之后在这个库里建表,只要不显式覆盖,都会继承 utf8mb4。这一步的作用是让后续导入的每个表都有统一的字符集基线,避免出现一张表 latin1、一张表 utf8 的混乱局面。

这块的玄学在于:你看到的乱码未必来自文件本身,而是来自连接层。MySQL 客户端和服务端之间的字符集转换是有状态的,如果客户端连接时用了 gbk,服务端按 utf8mb4 解析,内容就串了。所以导入完成后,第一步不是急着数行数,而是先抽一条数据肉眼验字符。

2.2 文件结构与字段预判:用建表语句反向推断

9 个 SQL 文件的命名有规律:authors.tang.sql、authors.song.sql明显是作者表,按朝代拆开;poet.tang.0.sql、poet.song.75000.sql这类是诗词正文表,按文件名区分朝代和分片。但具体表名叫什么、有哪些字段、主键怎么定义,不能靠猜。SQL 文件本身就是最好的说明书。

在 Linux 或 macOS 终端下可以用这几条命令快速摸底:

wc -l *.sql head -n 60 poet.tang.0.sql grep -i "CREATE TABLE" *.sql

逻辑说明:wc -l统计每个文件的行数,这个数值能帮你预估导入耗时。head -n 60看文件开头的 60 行,SQL 文件的头部通常会包含 SET NAMES、DROP TABLE IF EXISTS、CREATE TABLE 定义和少量 INSERT 示例。grep -i "CREATE TABLE"一次性列出所有文件中定义的表名,不用逐个打开就能掌握全貌。

参数说明:wc -l的-l是 count lines 的意思;head -n 60的-n指定行数;grep -i中的-i忽略大小写,因为 SQL 关键字可能写法不统一。这三条命令组合起来,能在 10 秒内帮你判断文件是否完整、表结构是否合理、导入顺序是否依赖。

典型情况下,这种诗词库的诗词表字段大致为:id主键、title标题、author作者、content正文、dynasty朝代、type体裁。作者表则是id、name、dynasty、intro这类设计。拿到建表语句后,我还会手动执行一条抽样查询验证字段是否真的是中文而不是 base64 或拼音缩写。

2.3 文件名里的数字陷阱:分片区间与行数的区别

poet.song.75000.sql、poet.song.194000.sql这类文件名里的数字很容易让人误读成“这个文件里有七万五千行”。但如果摘要描述里宋词总共才约两万首,一个分片怎么可能单独装下七万五千首?这个数字更合理的解释是分片 ID 区间或者导入序号,不是行数。

所以启动导入之前,我习惯先建一个临时数据库做全量导入,然后跑一次聚合查询摸清真实体量:

SELECT dynasty, COUNT(*) FROM poet GROUP BY dynasty;

逻辑说明:这条 SQL 按朝代分组统计诗词数量,用来核对摘要里“唐诗约 5.5 万首、宋词约 2.1 万首”的口径是否与文件一致。如果发现偏差,优先怀疑分片文件被重复导入,而不是怀疑摘要写错。

参数说明:GROUP BY dynasty要求该字段存在且值规范,如果建表字段不叫dynasty而是poet_type之类,需要先SHOW COLUMNS FROM poet;看真实字段名。这一步做完,你对这份资源的预期才算校准。

3. 导入执行:命令行与图形化的完整操作顺序

环境准备就绪后,进入实操。这一章讲两种导入姿势——命令行和图形化工具,以及导入完成后的表间关系处理。核心原则是:按依赖顺序导入,先作者表后诗词表,避免边导边报错。

3.1 命令行导入:source 与 shell 重定向的取舍

命令行导入是后端工程师最常用的方式,尤其适合文件较大、需要反复调试的场景。两条路都能走:一是进入 mysql 客户端后用source命令,二是直接用 shell 的重定向把文件灌进库。先导入作者表:

mysql -uroot -p --default-character-set=utf8mb4 gushici < /data/sql/authors.tang.sql mysql -uroot -p --default-character-set=utf8mb4 gushici < /data/sql/authors.song.sql

逻辑说明:<重定向让 mysql 客户端把文件内容当成 SQL 逐条执行。必须先导作者表,因为诗词表里大概率有作者字段,如果作者表存在外键约束(虽然很多开源库不建物理外键),先导诗词会造成违反约束的报错。即便没有物理外键,先导作者表也能保证后续关联查询的完整性。

参数说明:--default-character-set=utf8mb4显式指定客户端字符集,这是命令行导入最容易漏的参数。漏掉的后果是文件里的中文按 latin1 解析入库,查询结果全是乱码。-uroot -p是用户名和密码提示,生产环境不建议明文密码。

诗词表文件较大,逐个导入时我习惯用source而不是重定向,原因只有一个:source 出错时能看到更清晰的错误上下文,定位到具体行号:

USE gushici; SOURCE /data/sql/poet.tang.0.sql; SOURCE /data/sql/poet.song.75000.sql; SOURCE /data/sql/poet.song.82000.sql; SOURCE /data/sql/poet.song.125000.sql; SOURCE /data/sql/poet.song.150000.sql; SOURCE /data/sql/poet.song.158000.sql; SOURCE /data/sql/poet.song.194000.sql; SOURCE /data/sql/poet.song.63000.sql;

逻辑说明:USE gushici切换当前库,SOURCE是 mysql 客户端的内置命令,逐条读取文件里的 SQL 执行。这组顺序把 8 个诗词分片按文件名依次导入,没有强依赖顺序,因为都是 INSERT 语句。

参数说明:SOURCE后面的路径必须是 mysql 客户端所在机器能访问的绝对路径,不能是相对路径。如果你在 Windows 上用 cmd 操作,路径分隔符建议用正斜杠/避免转义问题。

导入完成后立刻验证行数,这是判断导入是否成功的最低标准:

SELECT COUNT(*) FROM poet; SELECT COUNT(*) FROM authors;

逻辑说明:这两条语句统计两个核心表的行数。如果poet表行数明显异常(比如为 0),优先检查导入顺序和文件路径,不要急着DROP TABLE。

3.2 图形化导入:Workbench 与 Navicat 的操作路径

不习惯命令行的读者可以用 MySQL Workbench 或 Navicat,步骤差异不大。Workbench 的路径是 Server 菜单下的 Data Import,选 Import from Self-Contained File,然后选目标库。Navicat 更直接——右键目标数据库,选“运行 SQL 文件”。

两个工具有一个共通陷阱:字符集设置藏在二级菜单里。Workbench 的 Data Import 面板里有个 Advanced 选项,Navicat 的运行 SQL 文件窗口底部有字符集下拉框,默认可能是 UTF-8 的别名实现或者干脆是空。我建议无论工具显示什么,都手动选一次utf8mb4,这不花时间但能省掉事后清乱码的大把功夫。

图形化工具还有个隐藏问题:超大文件容易让界面假死。如果某个分片文件超过 200MB,Workbench 的导入进度条可能长时间不动,这不是死机,是客户端在解析大事务。遇到这种情况,切回命令行导入反而更稳。

3.3 多分片合并:把 8 张诗词分片合成一张可检索的总表

9 个文件导入完成后,你会得到若干张表——poet可能是分片表名带后缀,也可能是多张独立表。对日常使用来说,分片结构不友好:查一句诗可能要跨表 UNION。我一般在导入完成后立刻建一张合并总表,把分片数据灌进去:

CREATE TABLE poet_all LIKE poet_tang; INSERT INTO poet_all SELECT * FROM poet_tang; INSERT INTO poet_all SELECT * FROM poet_song_75000; INSERT INTO poet_all SELECT * FROM poet_song_82000;

逻辑说明:CREATE TABLE ... LIKE完全复制原表的结构,包括字段、索引和字符集定义,这一步保证了合并表的物理结构一致。INSERT INTO ... SELECT将分片数据逐批迁入总表,不需要手动指定字段映射,因为前后表结构一致。

参数说明:这里表名poet_tang、poet_song_75000是示例,实际表名以SHOW TABLES;出的结果为准。如果分片表名里带点号(比如建表时直接叫poet.song.75000),引用时必须用反引号包裹:`poet.song.75000`,否则 MySQL 会把它解析成“库.表”结构。

合并完成后,poet_all就是你的单一查询入口,之后所有业务查询都打在总表上,逻辑简单、索引可控。这一章操作完之后,你的数据库已经具备了一个可检索古诗词库的基本形态。

4. 避坑:导入与查询环节的高频翻车现场

这段内容来自我处理多份语料库资源攒下的血泪经验,每条都对应一个真实故障。按“现象 → 原因 → 解决”的格式记录,方便你对照排查。

4.1 导入阶段的翻车现场

第一个坑:重复执行导致主键冲突。现象是ERROR 1062 (23000): Duplicate entry '75001' for key 'PRIMARY',导入中断。原因是同一个分片文件被导入了两次,第一次已经写入了部分数据,第二次执行时主键重复。解决办法不是跳过错误,而是先确认这张表是否有业务价值——如果是刚导完发现重复,直接 DROP TABLE 重建重导;如果已经掺了别的数据,用DELETE FROM poet WHERE id IN (SELECT id FROM poet GROUP BY id HAVING COUNT(*) > 1);清重再补唯一索引。

第二个坑:整张表的中文变成问号。现象很直观——查出来的诗句全是???,一眼扫过去像乱码。原因大概率是连接层字符集没对上,文件里存的是 utf8mb4,客户端却用 latin1 解析后写入。解决办法:先SHOW VARIABLES LIKE 'character_set_client';确认连接字符集,再用SET NAMES utf8mb4;重设当前会话,之后重新导入受影响的表。注意,已经变成问号的数据没法靠改会话恢复,必须重导。

第三个坑:大文件导入超时中断。现象是导入到中途报Lost connection to MySQL server during query或者ERROR 2013。原因是客户端的max_allowed_packet或net_read_timeout太小,大 INSERT 语句超过限制被切断。解决办法是在导入前把超时参数调大:

SET GLOBAL max_allowed_packet = 1073741824; SET GLOBAL net_read_timeout = 300; SET GLOBAL net_write_timeout = 300;

逻辑说明:max_allowed_packet限制单条 SQL 的最大包大小,单位是字节,这里设成 1GB;net_read_timeout和net_write_timeout是网络读写超时,单位秒,设 300 秒给大事务留足时间。参数说明:这些是全局变量,需要 SUPER 权限,改完当前连接需重连才生效。

4.2 查询阶段的翻车现场

第四个坑:带点号表名查询报错。现象是SELECT * FROM poet.song.75000直接提示Table 'gushici.poet' doesn't exist。原因是 MySQL 把poet.song.75000里的点号解析成了库表分隔符。解决办法是给表名加反引号:SELECT * FROM `poet.song.75000`;,或者像第 3.3 节那样建一个不带点号的总表。个人强烈推荐后者,靠反引号活着迟早出事。

第五个坑:用 REGEXP 搜生僻字直接慢到怀疑人生。现象是SELECT * FROM poet WHERE content REGEXP '月' LIMIT 10;在几十万行的表上跑了 3 秒以上。原因是 REGEXP 全表扫描,无法使用索引。解决思路分两层:如果只是应急单次查询,加LIMIT约束并接受慢;如果是高频业务查询,必须建全文索引,具体做法在下一章展开。

避坑这一章的核心逻辑其实只有一句:SQL 文件导入出问题,先查字符集,再查重复执行,最后才怀疑文件本身损坏。这个排查顺序能解决 80% 的导入故障。

5. 把诗词库做成可检索的服务:全文索引与飞花令玩法

数据落库只是起点,真正产生价值的是检索效率。古诗词场景里最常见的查询是“包含某个字的句子”——飞花令玩法、诗词接龙、主题检索,全部依赖这种查询。但 MySQL 的LIKE '%月%'和REGEXP在这类查询上都很慢,因为它们在几十万行里做全表扫。正确做法是建全文索引,并且必须用 ngram 解析器。

ALTER TABLE poet_all ADD FULLTEXT INDEX ft_poet_ngram (title, content) WITH PARSER ngram;

逻辑说明:这句 SQL 在poet_all表的title和content两个字段上建立全文索引,WITH PARSER ngram指定中文分词解析器。MySQL 默认的全文解析器按空格分词,对中文无效(中文没有空格),ngram 会把句子拆成连续 N 个字的序列,默认 N=2,也就是 bigram。

参数说明:ngram的分词长度默认是 2,适合诗词搜索;如果你想按单字搜索(比如飞花令必须单字匹配),需要修改ngram_token_size全局变量为 1。注意这个参数是只读全局变量,必须要修改 MySQL 配置文件并重启才能生效,不能动态SET。

索引建好后,查询语法要从LIKE换成MATCH ... AGAINST:

SELECT title, author, LEFT(content, 30) FROM poet_all WHERE MATCH(title, content) AGAINST('月' IN NATURAL LANGUAGE MODE) LIMIT 10;

逻辑说明:MATCH(title, content)针对之前建的双字段全文索引检索,AGAINST指定关键词,IN NATURAL LANGUAGE MODE表示自然语言模式,适合普通搜句场景。检索时会返回相关性排序的结果,前十个片段展示在LEFT(content, 30)截取的首 30 字预览里。

参数说明:LIMIT 10是安全阀,防止返回全表匹配结果。如果ngram_token_size是默认的 2,那么搜“月”会被 ngram 处理为词组匹配,结果可能不准;这也是我把这个参数单独拎出来说的原因——飞花令场景必须改成 1。

我早期做诗词检索功能时没注意到 ngram 长度,按默认配置建索引,结果MATCH AGAINST查“月”几乎查不到数据,一度怀疑是文件导入有遗漏,折腾了很久才反应过来是分词粒度问题。从那以后,我每建一个全文索引,都会强制先查一遍SHOW VARIABLES LIKE 'ngram_token_size',再做一轮真实关键词验证,而不是建完索引就当收工。索引对查询性能的改善是立竿见影的,同样查“月”,全文索引上了之后单次响应从秒级降到毫秒级,这才是这份古诗词库真正被盘活的样子。希望这篇拆解能让你少走几个弯路,顺利把唐诗宋词跑起来。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询