
简介古诗词数据库是一份面向诗词爱好者、开发者与研究工作者的MySQL数据资源内置从古至今近30万首诗词作品字段涵盖题目、作者、朝代、正文、注释、韵脚、流派等为诗词检索、教学演示和文本分析提供基础数据支撑。压缩包共1个文件即以sql格式存储的完整建表与导入脚本整体体积43.55MB解压后可直接导入本地MySQL环境生成数据表便于按需查询与研究。目前已有3396人学习/下载。借助这套数据使用者无需自行爬取整理即可快速搭建诗词库既能按作者、朝代、流派等维度筛选作品也可用于诗词风格统计、韵律分析或文化科普站点的内容储备对开展古典文学数字化项目与课堂教学都较为实用。配合注释和作者简介字段还能辅助理解诗词背景为不同研究课题提供灵活入口。 做古诗词类内容产品最绕不开的是数据从哪来。网上能搜到的诗词库不少但真正拿回来能用、字段设计合理、导入不折腾的mysql数据表并不多。这套古诗词数据库是我整理过好几轮之后沉淀下来的版本覆盖先秦到近现代诗词总量在30万首以上诗人数量超过5万位结构上做了比较彻底的拆表和索引优化能直接支撑诗词搜索、飞花令、作者作品集、朝代筛选这类常见需求。无论你是要做小程序、诗词教学系统、App后端还是只想搭个网站做数据可视化这套表都能省掉大量从零清洗数据的时间。下面把表结构设计、导入步骤和实际使用中踩过的坑一次说清楚。1. 项目定位与设计思路1.1 为什么值得专门整理一套“古诗词mysql库”诗词数据看起来就是“标题、作者、正文、朝代”四个字段真拿来做业务的时候会发现远远不够。比如用户想按“送别”找诗想按“婉约派”筛选词人想统计某个朝代的诗词数量趋势甚至要做诗词接龙、关键字对仗这些都需要对原始文本做二次加工和结构化拆解。我一开始也图省事直接用网上扒下来的单一csv表结果正文和注释混在一起作者字段里带着生卒年标点符号全角半角混用一到查询就像拆盲盒。后来决定按业务场景重新设计表结构把诗人信息、诗词主体、分类标签拆成独立表再通过外键关联起来。这样做最大的优势是数据冗余降到最低查询路径清晰后续不管做Redis缓存还是Elasticsearch索引都可以从mysql这层直接导出格式化数据。整体看下来这套结构对“教学检索”和“内容展示”两类场景的适配性都很好应用层代码写起来也舒服不需要在业务代码里反复做字符串截断和正则清洗。1.2 数据分层三张核心表加两张辅助表整套库由五张表组成。诗词主表存正文和标题诗人表存作者背景分类表维护标签信息诗词分类关联表做多对多映射另外还有一张朝代表作为维度表。在设计初就把“多对多”关系理清楚避免把标签直接拼进诗词表的一个字段里否则后面要统计“咏物诗里数量最多的前十个诗人”这种需求时SQL会写到你怀疑人生。朝代表单独拆出来也是吃过亏之后的改进。以前朝代直接以varchar形式存在诗词表里每次按朝代聚合都要先处理字符串分布不均的问题像“北宋”“宋”“南宋”这种相近但不一致的写法聚合结果必然不准确。拆成独立表之后诗词表只存朝代ID展示时再关联查询名称从源头保证了数据口径一致。2. 数据表结构设计与字段解析2.1 诗人表避免重复存储的生平信息诗人表的数据来源是各类公开的文学史资料字段包含姓名、字号、所属朝代ID、籍贯、生平简介和作品数量统计。作品数量不直接实时count而是定期更新一个冗余字段这样在诗人列表页做排序时不需要每次都聚合诗词表性能提升非常明显。CREATE TABLE poet ( id int unsigned NOT NULL AUTO_INCREMENT COMMENT 诗人ID, name varchar(30) NOT NULL COMMENT 姓名, zi varchar(50) DEFAULT NULL COMMENT 字, hao varchar(50) DEFAULT NULL COMMENT 号, dynasty_id smallint unsigned NOT NULL COMMENT 所属朝代ID, birth_year varchar(20) DEFAULT NULL COMMENT 生年存在争议时存区间文本, death_year varchar(20) DEFAULT NULL COMMENT 卒年, hometown varchar(100) DEFAULT NULL COMMENT 籍贯, intro text COMMENT 生平简介, poem_count int unsigned NOT NULL DEFAULT 0 COMMENT 作品数量冗余字段, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_dynasty (dynasty_id), KEY idx_name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci COMMENT诗人表;注意这里的birth_year字段没有用int因为古代诗人的生卒年份在史料里经常有争议比如“约公元701年”这种表述用int存不了用varchar存成“约701年”反而更接近原始资料的语义。这也是诗词类数据很典型的处理方式不能用现代人“出生日期”的思维硬套。2.2 诗词表正文与标题的完整存储诗词表是整个库的核心20多个字段涵盖了从标题、正文到韵律、注释、赏析的完整信息。这里几个关键设计说一下。正文用text类型存储保留原文中的换行和标点不做任何清洗因为展示层需要保留诗词的原始排版节奏。字段dynasty_id和poet_id都有索引这是数据量上去之后高频查询的命脉。另外专门设计了style字段标记“诗”“词”“曲”“赋”rhythm字段存词牌名或曲牌名比如“水调歌头”“念奴娇”这对词曲类内容尤其重要用户按词牌名筛选是高频场景。is_classic字段用来标记中小学教材收录篇目做教育类产品时可以直接用它过滤出“必背诗词”集合。CREATE TABLE poem ( id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 诗词ID, poet_id int unsigned NOT NULL COMMENT 诗人ID, dynasty_id smallint unsigned NOT NULL COMMENT 朝代ID, title varchar(200) NOT NULL COMMENT 标题, content text NOT NULL COMMENT 正文保留原文换行和标点, style varchar(10) DEFAULT 诗 COMMENT 体裁诗/词/曲/赋, rhythm varchar(50) DEFAULT NULL COMMENT 词牌名/曲牌名, type varchar(100) DEFAULT NULL COMMENT 主题类型如送别、怀古、边塞, is_classic tinyint(1) NOT NULL DEFAULT 0 COMMENT 是否教材必背篇目, annotation text COMMENT 注释, appreciation text COMMENT 赏析, views int unsigned NOT NULL DEFAULT 0 COMMENT 浏览量, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_poet (poet_id), KEY idx_dynasty_style (dynasty_id, style), KEY idx_rhythm (rhythm), KEY idx_type (type), FULLTEXT KEY ft_content (content) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci COMMENT诗词主表;2.3 分类关联表与朝代表支撑多维筛选分类表存的是“送别”“思乡”“山水田园”“边塞”“爱情”“哲理”这类主题标签每个标签都有独立的ID和描述。分类和诗词的关系是典型的多对多一首诗可以既属于“送别”又属于“友情”所以单独建一张关联表来维护映射避免在诗词表里拼字符串数组。朝代表就比较简单就是常见朝代列表加起止年份。这里要说明年份范围不宜写得太精确比如“隋”写“581-619”没问题但“五代十国”这种复杂时期建议直接存一个描述字符串强行拆起止年份反而会在后续做时间轴可视化时产生误导。CREATE TABLE dynasty ( id smallint unsigned NOT NULL AUTO_INCREMENT, name varchar(20) NOT NULL, start_year varchar(20) DEFAULT NULL, end_year varchar(20) DEFAULT NULL, description varchar(255) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT朝代表;3. 数据导入与库表配置实操3.1 准备阶段版本选择与字符集设置我推荐mysql使用8.0以上版本。8.0的默认字符集是utf8mb4对生僻字、冷门繁体字支持更完整古诗词数据里常见“叆”“叇”这类生僻字用老版本的utf8会直接变成问号。另外8.0的窗口函数和通用表表达式在写排名、去重、递归查询时比5.7顺手很多后续做数据分析能少绕很多弯。如果你还没装mysql装完之后第一件事就是确认字符集。SHOW VARIABLES LIKE character_set_server; SHOW VARIABLES LIKE collation_server;目标值应该是utf8mb4和utf8mb4_unicode_ci或utf8mb4_general_ci。如果不对修改my.cnf配置文件里[mysqld]部分的character-set-server重启后重新确认。这一步没做对后面导入中文必乱码而且排查起来非常痛苦。3.2 导入数据表的三种方式对比拿到.sql文件后导入方式有三种实测下来各有适用场景。第一种是命令行source方式适合中等体积的库文件直接进mysql客户端执行source /path/to/gushici.sql;能看到每一条SQL的执行反馈哪里报错一目了然。缺点是如果文件里有语法兼容问题中断之后要手动排查进度。第二种是图形化工具导入Navicat或mysql workbench都支持。workbench里选Server菜单下的Data Import选择“Import from Self-Contained File”指向.sql文件即可。大文件导入时workbench的进度条有时会卡住不动但底层其实还在跑需要耐心等。第三种是备份恢复方式mysql -u root -p gushici.sql这种方式最接近服务器间迁移的姿势适合部署到生产环境时用但前提是sql文件本身格式要规范不能混入乱七八糟的注释和多余字符。我自己的习惯是先在本地用source方式完整导入验证一遍确认表结构和数据量都没问题之后再打包成压缩文件到服务器上用命令行恢复双保险。3.3 核心查询SQL示例排序、统计、模糊搜索数据导入完成后验证数据有效性最直接的方式就是跑几条查询。比如查“苏轼的诗词里收录的最长的五首诗”按正文长度排序SELECT title, CHAR_LENGTH(content) AS len FROM poem WHERE poet_id (SELECT id FROM poet WHERE name 苏轼) ORDER BY len DESC LIMIT 5;查“各朝代诗词数量分布”并高亮TOP10SELECT d.name, COUNT(p.id) AS cnt FROM poem p JOIN dynasty d ON p.dynasty_id d.id GROUP BY d.name ORDER BY cnt DESC LIMIT 10;全文检索可以走MATCH...AGAINSTSELECT id, title, LEFT(content, 80) AS excerpt FROM poem WHERE MATCH(content) AGAINST(大漠孤烟 IN NATURAL LANGUAGE MODE) LIMIT 20;注意全文索引不支持中文分词整条内容作为一个连续的词去匹配。对于“大漠孤烟”这种四字短语结果比较准确但搜单字或双字时因为中文没有天然空格分词匹配覆盖率会受限制。如果你想做更精细的搜索建议把数据库中的数据同步一份到Elasticsearch或使用支持中文分词的组件mysql这层负责基础过滤就行。4. 常见问题与排查技巧实录4.1 中文乱码源头字符集没设对导入后查询发现中文字段全是???大概率是建表时用了utf8而不是utf8mb4或者连接层字符集没统一。用以下命令确认SHOW FULL COLUMNS FROM poem;看Collation列是否为utf8mb4_unicode_ci。如果是utf8_general_ci建表语句需要调整。还要注意客户端连接时的字符集设置连接之后执行SET NAMES utf8mb4;这一步是很多人容易漏掉的。实测中最隐蔽的坑是原始sql文件本身的编码格式不是utf8可能是GBK或带BOM的UTF-8。用file gushici.sql命令可以查看文件编码如果显示ISO-8859或GBK导入前先用文本编辑器做一次转码。4.2 导入性能慢与锁表问题30万条数据全量导入如果一条一条INSERT时间会非常漫长而且中途报错很难定位。我实测第一次导入时用了大概40多分钟后来改成在source前临时关闭唯一性检查和自动提交时间缩短到不到10分钟SET autocommit0; SET unique_checks0; SET foreign_key_checks0; -- 执行导入脚本 SET autocommit1;另外导入过程中InnoDB的行锁和间隙锁会影响并发读写如果线上有服务在跑建议用mysqldump的--single-transaction参数做在线备份导入或者直接安排在业务低峰期操作。导入完成之后记得手动执行一次OPTIMIZE TABLE poem;重建索引碎片化这一步能明显改善后续查询延迟。4.3 字段设计导致的统计口径问题诗词表里有一类坑叫“一人多名”。比如苏轼古人称他为苏东坡、苏文忠字子瞻号东坡居士。如果你在诗人表里只存一个name字段用户搜“苏东坡”就搜不到数据。我的解决方案是导入时把“字”“号”字段联合起来在查询层做别名匹配。还有一个问题就是作品归属的争议。同一首诗在不同古籍里有时署名为不同作者比如《静夜思》在个别版本里标记为“李白”没问题但部分古人也写过异文。遇到这种数据我建议保留“存疑”状态不要强行二选一。可以在诗词表加一个is_verified字段标记审核状态宁可展示“作者存疑”也不要在数据层面丢失信息。4.4 排序与去重别被int显示宽度迷惑很多人看到表结构里int(5)会误以为这是限制数据最大长度为5位。其实int后面的数字只是显示宽度不影响存储范围mysql中int类型固定占用4字节范围在正负21亿左右。如果你的诗词ID预估不会超过这个范围用int足够但保守起见我诗词表的主键直接用了bigint毕竟百万级数据在未来两三年内完全可能达到预留空间没有坏处。做去重时也要注意使用DISTINCT的语义。比如统计“一共有多少位诗人”和“有多少个不重复的朝代”这两个场景的SQL写法完全不同。尤其注意COUNT(DISTINCT poet_id)和COUNT(*)混用时如果不加条件很容易把“诗词总数”误读成“诗人总数”而写出错误的统计报告。4.5 客户端连接认证协议报错如果使用较老的客户端程序或第三方组件连接mysql 8.0经常会报Authentication plugin caching_sha2_password cannot be loaded这类错误。这是mysql 8.0默认插件与旧版客户端不兼容导致的。解决方案有两种一是升级客户端驱动到支持caching_sha2的版本二是把用户认证插件改回mysql_native_passwordALTER USER your_userlocalhost IDENTIFIED WITH mysql_native_password BY your_password; FLUSH PRIVILEGES;这种方式适合内网测试环境生产环境还是建议优先升级驱动安全性更高。4.6 数据库连接池与端口连接问题项目联调时最常遇到的就是“连不上数据库”。先确认mysql服务端口号是否改过默认是3306但有些服务器为安全会改成其他端口。排查思路按顺序来netstat -tlnp | grep mysql mysql -u root -p -h 127.0.0.1 -P 端口号如果本机能连、远端连不上优先检查防火墙和安全组是否放通了对应端口。连接池参数里有一个wait_timeout需要留意太短会导致连接在闲置时被mysql服务端断开应用层报异常连接池的核心参数像maxActive、initialSize要根据并发量调整不要照抄默认值。这套数据库表结构我在两个项目里实际落地过一次是诗词学习小程序一次是文化类内容管理后台。整体跑下来数据准确性和扩展性都够用尤其是分类表和朝代表的拆分让后来增加“按主题推荐关联诗词”的功能简单了很多。如果你拿到的诗词数据比我这套更全可以继续在poem表上增加字段比如“拼音标注”“英文翻译”或者“朗诵音频地址”结构不会受到影响。最后再分享一个小技巧导入完成后定期用CHECK TABLE poem;检查表健康状态配合mysqldump做定时备份这套数据用起来才能真正放心。本文还有配套的精品资源点击获取