一开始想用qwen 3.5来做,结果做成的是图形格式的PDF, 而且不能输出生成幻灯片的脚本,不太满意,于是让DeepSeek再做一版。
提示如下, 提纲是qwen输出的。
生成SQL优化方法介绍幻灯片。
优化维度:1. 索引优化基础与使用原则(合理创建B+树索引|避免在索引列上使用函数或计算);2. 查询语句写法规范与技巧(优先使用WHERE而非HAVING|避免SELECT *|善用LIMIT分页);3. 表结构设计基础规范(遵循三范式但适度反范式|合理选择数据类型|主键必设且用INT/UUID);4. 使用EXPLAIN分析执行计划(关注type、rows、key、Extra字段|识别ALL/Using filesort等警告);5. 避免全表扫描与常见性能陷阱(NULL值导致索引失效|LIKE '%abc'无法走索引|JOIN字段未建索引),最终凝练为"少查、快连、精索、常析、避坑"五大实战原则。
先输出第一个专题:索引。数据库中B+树索引的原理、创建、失效规避与实践验证方法;涵盖合理构建复合索引(如idx_user_status_time)、严防索引失效场景(禁止函数包裹、LIKE '%xxx'、隐式转换等)、通过EXPLAIN ANALYZE监控验证效果三大策略;深入解析索引底层结构、写法合规性对执行计划的影响,突出"索引要建得准、用得对、管得勤"。
用postgresql数据库举例,输出生成幻灯片的python代码。
首先根据代码中的提示安装
pip install manim
Installing collected packages: svgelements, pyglm, pydub, glcontext, watchdog, srt, soupsieve, skia-pathops, screeninfo, pyglet, pycairo, networkx, moderngl, mapbox-earcut, manimpango, isosurfaces, decorator, av, audioop-lts, moderngl-window, cloup, beautifulsoup4, manim
Successfully installed audioop-lts-0.2.2 av-16.1.0 beautifulsoup4-4.14.3 cloup-3.0.8 decorator-5.2.1 glcontext-3.0.0 isosurfaces-0.1.2 manim-0.19.2 manimpango-0.6.1 mapbox-earcut-2.0.0 moderngl-5.12.0 moderngl-window-3.1.1 networkx-3.6.1 pycairo-1.29.0 pydub-0.25.1 pyglet-2.1.13 pyglm-2.8.3 screeninfo-0.8.1 skia-pathops-0.9.2 soupsieve-2.8.3 srt-3.5.3 svgelements-1.9.6 watchdog-6.0.0
pip install manim-slides
Installing collected packages: XlsxWriter, rtoml, qtpy, MarkupSafe, python-pptx, jinja2, click-default-group, pydantic-extra-types, manim-slides
Successfully installed MarkupSafe-3.0.3 XlsxWriter-3.2.9 click-default-group-1.2.4 jinja2-3.1.6 manim-slides-5.5.4 pydantic-extra-types-2.11.0 python-pptx-1.0.2 qtpy-2.4.3 rtoml-0.13.0
执行命令行, 他生成的脚本有错,
manim -pql index_slides.py IndexOptimization
C:\Users\lt\AppData\Local\Programs\Python\Python313\Lib\site-packages\pydub\utils.py:170: RuntimeWarning: Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work
warn("Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work", RuntimeWarning)
...
TypeError: Code.__init__() got an unexpected keyword argument 'code'
TypeError: Code.__init__() got an unexpected keyword argument 'insert_line_no'
把错误信息提供给他,他把code改成text后仍然不对,自己到manim 官方文档页面查询,得知了正确的参数名是code_string,同样的,insert_line_no应该是add_line_numbers,并且不存在font_size参数,都改正后的脚本如下:
python
from manim import *
from manim_slides import Slide
# 配置中文字体,请根据系统环境调整
config.tex_template.add_to_preamble(r"\usepackage{ctex}")
config.tex_template.add_to_preamble(r"\usepackage{xcolor}")
class IndexOptimization(Slide):
"""PostgreSQL 索引优化专题幻灯片 - 索引篇"""
def construct(self):
# ---------- 标题页 ----------
title = Text("PostgreSQL 索引优化实战", font_size=48, color=BLUE)
subtitle = Text("第一专题:索引", font_size=36, color=GRAY)
authors = Text("少查·快连·精索·常析·避坑", font_size=28, color=GREEN)
VGroup(title, subtitle, authors).arrange(DOWN, buff=0.5)
self.play(Write(title))
self.play(FadeIn(subtitle, shift=UP))
self.play(FadeIn(authors, shift=UP))
self.wait(1)
self.next_slide() # 进入下一页
# 清除当前画面
self.clear()
# ---------- 1. B+树索引原理 ----------
principle_title = Text("1. B+树索引原理", font_size=40, color=YELLOW).to_edge(UP)
self.play(Write(principle_title))
# 绘制简单的B+树结构
root = Circle(radius=0.3, color=BLUE).shift(UP*3)
root_label = Text("根页", font_size=20).move_to(root)
leaf1 = Circle(radius=0.3, color=GREEN).shift(LEFT*3)
leaf2 = Circle(radius=0.3, color=GREEN).shift(LEFT*1)
leaf3 = Circle(radius=0.3, color=GREEN).shift(RIGHT*1)
leaf4 = Circle(radius=0.3, color=GREEN).shift(RIGHT*3)
leaf_label1 = Text("数据页1", font_size=16).next_to(leaf1, DOWN)
leaf_label2 = Text("数据页2", font_size=16).next_to(leaf2, DOWN)
leaf_label3 = Text("数据页3", font_size=16).next_to(leaf3, DOWN)
leaf_label4 = Text("数据页4", font_size=16).next_to(leaf4, DOWN)
arrows = VGroup(
Arrow(root.get_bottom(), leaf1.get_top(), buff=0.1),
Arrow(root.get_bottom(), leaf2.get_top(), buff=0.1),
Arrow(root.get_bottom(), leaf3.get_top(), buff=0.1),
Arrow(root.get_bottom(), leaf4.get_top(), buff=0.1),
)
tree = VGroup(root, root_label, leaf1, leaf2, leaf3, leaf4,
leaf_label1, leaf_label2, leaf_label3, leaf_label4, arrows)
tree.scale(0.8).shift(DOWN*1.5)
self.play(GrowFromCenter(root), Write(root_label))
self.play(*[GrowFromCenter(leaf) for leaf in [leaf1, leaf2, leaf3, leaf4]])
self.play(*[Write(lab) for lab in [leaf_label1, leaf_label2, leaf_label3, leaf_label4]])
self.play(*[GrowArrow(arr) for arr in arrows])
# 添加解释文字
explain = Text(
"B+树特点:\n- 所有数据在叶子节点\n- 叶子间双向链表连接\n- 高度平衡,3~4层即可支撑百万记录",
font_size=24, color=GRAY, line_spacing=1.2
).to_edge(RIGHT).shift(UP)
self.play(Write(explain))
self.wait(2)
self.next_slide()
# ---------- 2. 索引创建规范 ----------
self.clear()
create_title = Text("2. 索引创建规范", font_size=40, color=YELLOW).to_edge(UP)
self.play(Write(create_title))
# 表结构示例
table_code = Code(
code_string='''
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
status INT NOT NULL,
created_at TIMESTAMP NOT NULL,
email VARCHAR(255)
);
''',
language="sql",
#font_size=24,
background="window",
add_line_numbers=False
).shift(LEFT*3).scale(0.8)
# 复合索引推荐
idx_code = Code(
code_string='''
-- 推荐复合索引
CREATE INDEX idx_user_status_time
ON users(status, created_at);
-- 适合查询:
SELECT * FROM users
WHERE status = 1
ORDER BY created_at DESC;
''',
language="sql",
#font_size=24,
background="window",
add_line_numbers=False
).next_to(table_code, DOWN, buff=0.5)
self.play(FadeIn(table_code, shift=UP))
self.play(FadeIn(idx_code, shift=UP))
# 附加说明
note = Text(
"原则:\n- 等值条件列放前面\n- 排序/范围列放后面\n- 索引列不宜过多(5列内)",
font_size=24, color=BLUE, line_spacing=1.5
).to_edge(RIGHT)
self.play(Write(note))
self.wait(2)
self.next_slide()
# ---------- 3. 索引失效场景 ----------
self.clear()
invalid_title = Text("3. 严防索引失效场景", font_size=40, color=YELLOW).to_edge(UP)
self.play(Write(invalid_title))
# 用表格展示失效场景
table = Table(
[["函数包裹", "WHERE func(col) = value"],
["LIKE '%xxx'", "WHERE name LIKE '%abc'"],
["隐式转换", "WHERE phone = 123456 (phone是varchar)"],
["复合索引跳跃列", "跳过前导列直接查created_at"]],
col_labels=[Text("失效场景"), Text("错误示例")],
include_outer_lines=True,
line_config={"stroke_width": 1, "color": GRAY},
element_to_mobject_config={"font_size": 20}
).scale(0.7).shift(UP*1)
self.play(Create(table))
# 添加红色警示
warning = Text(
"后果: 全表扫描(ALL) | 性能急剧下降",
font_size=28, color=RED
).shift(DOWN*2)
self.play(Write(warning))
self.wait(2)
self.next_slide()
# ---------- 4. 通过EXPLAIN ANALYZE验证 ----------
self.clear()
explain_title = Text("4. EXPLAIN ANALYZE 验证效果", font_size=40, color=YELLOW).to_edge(UP)
self.play(Write(explain_title))
# 展示执行计划对比
plan_good = Code(
code_string='''-- 正确使用索引的计划
=> EXPLAIN ANALYZE SELECT * FROM users
WHERE status = 1 ORDER BY created_at;
--------------------------------------------------------------------
Index Scan using idx_user_status_time on users
(cost=0.15..8.17 rows=1 width=8)
(actual time=0.024..0.025 rows=1 loops=1)
Planning Time: 0.123 ms
Execution Time: 0.045 ms''',
language="sql",
#font_size=20,
background="window",
add_line_numbers=False
).shift(UP*0.5).scale(0.7)
plan_bad = Code(
code_string='''-- 函数包裹导致索引失效
=> EXPLAIN ANALYZE SELECT * FROM users
WHERE EXTRACT(YEAR FROM created_at) = 2023;
--------------------------------------------------------------------
Seq Scan on users
(cost=0.00..22.75 rows=4 width=8)
(actual time=0.078..0.139 rows=4 loops=1)
Planning Time: 0.234 ms
Execution Time: 0.176 ms''',
language="sql",
#font_size=20,
background="window",
add_line_numbers=False
).next_to(plan_good, DOWN, buff=0.3).scale(0.7)
self.play(FadeIn(plan_good, shift=LEFT))
self.play(FadeIn(plan_bad, shift=RIGHT))
# 高亮关键指标
circle_good = Circle(color=GREEN, radius=0.5).move_to(plan_good.get_center()+DOWN*0.5)
circle_bad = Circle(color=RED, radius=0.5).move_to(plan_bad.get_center()+DOWN*0.5)
self.play(Create(circle_good), Create(circle_bad))
note = Text("关注: type(Index Scan vs Seq Scan), actual time, rows", font_size=24).to_edge(DOWN)
self.play(Write(note))
self.wait(2)
self.next_slide()
# ---------- 5. 总结与实战原则 ----------
self.clear()
summary_title = Text("索引优化五大原则", font_size=44, color=YELLOW).to_edge(UP)
self.play(Write(summary_title))
principles = VGroup(
Text("1️⃣ 建得准: 根据查询模式设计复合索引 (如idx_user_status_time)", font_size=28),
Text("2️⃣ 用得对: 避免函数、隐式转换、前导模糊", font_size=28),
Text("3️⃣ 管得勤: 定期用EXPLAIN ANALYZE验证, 删除冗余索引", font_size=28),
Text("4️⃣ 覆盖索引: 考虑包含列(INCLUDE)减少回表", font_size=28),
Text("5️⃣ 监控: pg_stat_user_indexes 查看使用率", font_size=28),
).arrange(DOWN, aligned_edge=LEFT, buff=0.3).shift(UP*0.5)
for p in principles:
self.play(Write(p, lag_ratio=0.1))
self.wait(0.3)
footer = Text(
"下一专题预告: 查询语句写法规范与技巧",
font_size=24, color=GRAY
).to_edge(DOWN)
self.play(Write(footer))
self.wait(3)
# 如果要生成视频幻灯片,需安装 manim 和 manim-slides,然后运行:
# manim -pql index_slides.py IndexOptimization
# manim-slides indexoptimization
另外,下载ffmpeg, 将压缩包解压到C:\d\ffmpeg\bin,添加到PATH环境变量。
wget https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.7z
Saving to: 'ffmpeg-release-essentials.7z'
set path=%path%;C:\d\ffmpeg\bin
再次执行就成功生成了mp4格式的幻灯片。
INFO Rendered IndexOptimization scene.py:278
Played 39 animations
[02/17/26 17:19:55] INFO Previewed File at: file_ops.py:237
'C:\d\media\videos\index_slides\480p15\IndexOptimization.mp4'
[02/17/26 17:19:58] INFO Generated 6 slides to 'C:\d\slides\files\IndexOptimization' base.py:599
[02/17/26 17:19:58] INFO Generated 6 slides to 'C:\d\slides\files\IndexOptimization' base.py:599
INFO Slide 'IndexOptimization' configuration written in base.py:611
'C:\d\slides\IndexOptimization.json'
INFO Slide 'IndexOptimization' configuration written in base.py:611
'C:\d\slides\IndexOptimization.json'
第二个命令行还是报错,看提示是缺少qt包,暂时不管了。
manim-slides indexoptimization
Traceback (most recent call last):
...
qtpy.QtBindingsNotFoundError: No Qt bindings could be found