沙箱的系统表里没有「过程」这一类对象,所以查不到是正常的。
MySQL 有三种查法:SHOW STATUS 看清单、SHOW CREATE 看源码、
information_schema 写脚本。
第三种最适合进脚本:它是普通查询,能加 WHERE、能 JOIN、能导出。
14.3 讲两种查法,教材只给了 SHOW STATUS 和 SHOW CREATE。这一篇补上第三种:数据字典。
上一篇讲怎么调,这一篇讲怎么查,下一篇讲怎么改。
三篇的顺序其实就是日常维护的顺序:用、查、改。
一、沙箱的系统表里没有这一类对象
查 sqlite_master 按类型分组,只有一条 table 记录。
没有 procedure、没有 function——引擎里根本没有这类对象,自然也查不到。
| 对象类型 | 数量 |
|---|---|
table |
1 |
index |
0(主键就是 rowid) |
view |
0 |
MySQL 那边这些对象存在数据字典里(老版本是 mysql.proc 表),
外面能看到的是 information_schema.ROUTINES 这张系统视图。
「存在数据字典里」这件事很重要:它意味着过程和表一样,是「可以被查询的对象」,
而不是「只在内存里的代码」。所以它能被备份、被导出、被比对。
二、MySQL 的三种查法
SHOW PROCEDURE STATUS WHERE Db = 'shop';
SHOW CREATE PROCEDURE p_list_cat;
第一种给清单:名字、类型、创建时间、注释。第二种给源码。 两个配合起来,正好是「先找到、再看清」。
SELECT ROUTINE_NAME, ROUTINE_TYPE, CREATED
FROM information_schema.ROUTINES
WHERE ROUTINE_SCHEMA = 'shop';
| 查法 | 能看到什么 |
|---|---|
SHOW PROCEDURE STATUS |
清单:名字、类型、时间、注释 |
SHOW CREATE PROCEDURE |
源码 + 建它时的环境 |
information_schema |
可筛选,能写进脚本 |
第三种最适合进脚本:它是普通查询,能加 WHERE、能 JOIN、能导出成表格。
前两种是给人在命令行里看的,格式固定,不好二次处理。
三、复刻版的过程清单
沙箱这边用一张小表当「数据字典」,存名字、参数个数、注释。
这张表就是 SHOW PROCEDURE STATUS 的等价物。
| 过程名 | 参数个数 | 注释 |
|---|---|---|
p_list_cat |
1 | 按类别列商品 |
p_stock |
1 | 查库存 |
为什么要费劲记这些东西?因为「过程在哪、谁建的、干什么的」是维护时的第一问。 真实环境里这些信息由数据字典维护,我们可以直接查。
四、查参数与源码
参数名和源码都能查出来:参数从函数签名里读,源码在建的时候存下来。
对应 MySQL 的 SHOW CREATE PROCEDURE——它同时给源码和参数。
| 过程名 | 参数 | 源码开头 |
|---|---|---|
p_list_cat |
cat_id |
CREATE PROCEDURE ... |
p_stock |
gid |
CREATE PROCEDURE ... |
这里有个实践上的提醒:源码最好自己另存一份。
因为 SHOW CREATE 出来的不一定是你当初写的那份——sql_mode、字符集都会被记下来,
而且一旦有人在服务器上改过,你本地那份就是旧的了。
所以不少团队会把过程源码也放进版本库,跟应用代码一起走发布流程。
这一条在下一篇「改过程」里还会用到。
五、查「正在跑的过程」
SHOW PROCESSLIST;
SELECT ID, TIME, STATE, INFO FROM information_schema.PROCESSLIST
WHERE INFO LIKE '%p_list_cat%';
过程跑起来之后,PROCESSLIST 里看到的是「它里面正在执行的那条 SQL」,不会是过程名。
这一点常让人以为过程没在执行——其实是在执行,只是显示的是里面那句。
所以想筛「谁在跑我的过程」,得按里面那句 SQL 的特征去 LIKE,
或者提前在过程里加注释标记。
沙箱是单进程内嵌的,没有「连接列表」这个概念,这一节只能看原码。
六、动手 Demo:查清单、查源码、查参数
这一段先证「沙箱的系统表里没有过程」,再把三种 MySQL 查法贴成原码,最后用一张小表 + 函数签名, 把「清单」和「源码」这两件事在沙箱里做出来。
import sqlite3, inspect
c = sqlite3.connect(u":memory:")
# ① 沙箱的系统表里没有过程这一类
print(c.execute(u"SELECT type, COUNT(*) FROM sqlite_master "
u"GROUP BY type").fetchall())
# ② 拿一张小表当「数据字典」
REG = {}
def create(name, fn, code, comment=u""):
REG[name] = {"fn": fn, "code": code, "comment": comment,
"params": list(inspect.signature(fn).parameters)}
def list_by_cat(cat_id):
return c.execute(u"SELECT id, name FROM tb_goods WHERE cat_id = ?",
(cat_id,)).fetchall()
create(u"p_list_cat", list_by_cat,
u"CREATE PROCEDURE p_list_cat(IN c INT) BEGIN ... END",
comment=u"按类别列商品")
# ③ 查清单
for k, v in REG.items():
print(k, len(v["params"]), v["comment"])
# ④ 查参数与源码
for k, v in REG.items():
print(k, v["params"], v["code"][:34])
实跑输出:
--------------------------------------------------------------------
第六十二课:想看一个过程长什么样,得先知道它在哪
--------------------------------------------------------------------
**教材 14.3 讲两种查法:`SHOW STATUS` 看列表、`SHOW CREATE` 看源码。**
**沙箱连过程都没有,这两种查法自然无从谈起。**
**这一课换个角度:先证「沙箱查不到」,再讲清 MySQL 那边到底存在哪。**
一、沙箱的系统表里没有这一类对象
--------------------------------------------------------------------
对象类型 数量
--------------
table 1
**只有一条 `table` 记录。连索引都没有——主键就是 rowid,不单独占一条。**
**没有 procedure、没有 function 这两类——因为引擎里根本没有这类对象。**
**MySQL 那边它们存在 `mysql.proc`(老版本)或数据字典里,**
**外面能看到的是 `information_schema.ROUTINES` 这张视图。**
二、MySQL 的三种查法
--------------------------------------------------------------------
[教材原码 · 本沙箱不执行]
| SHOW PROCEDURE STATUS WHERE Db = 'shop';
教材原码,列出库里的过程:名字、类型、创建时间、注释
[教材原码 · 本沙箱不执行]
| SHOW CREATE PROCEDURE p_list_cat;
教材原码,看源码:sql_mode、字符集、完整的 CREATE 语句
[教材原码 · 本沙箱不执行]
| SELECT ROUTINE_NAME, ROUTINE_TYPE, CREATED
| FROM information_schema.ROUTINES
| WHERE ROUTINE_SCHEMA = 'shop';
教材原码,第三种查法:直接查数据字典
查法 能看到什么
-----------------------------------------------------
`SHOW PROCEDURE STATUS` 清单:名字、类型、时间、注释
`SHOW CREATE PROCEDURE` 源码 + 建它时的环境
`information_schema` 可筛选,能写进脚本
**第三种最适合写进脚本:它是普通查询,能加 `WHERE`、能 `JOIN`、能导出。**
**前两种是给人在命令行里看的。**
三、复刻版的「过程清单」
--------------------------------------------------------------------
过程名 参数个数 注释
----------------------------------
p_list_cat 1 按类别列商品
p_stock 1 查库存
**这张表就是 `SHOW PROCEDURE STATUS` 的等价物:名字、参数个数、注释。**
**真实环境里这些东西存在数据字典里,我们可以直接查。**
四、查参数与源码
--------------------------------------------------------------------
过程名 参数 源码开头
-------------------------------------------------------
p_list_cat cat_id CREATE PROCEDURE p_list_cat(IN c I…
p_stock gid CREATE PROCEDURE p_stock(IN gid IN…
**参数名是从函数签名里 `inspect` 出来的,源码是建的时候存下来的。**
**对应 MySQL 的 `SHOW CREATE PROCEDURE`:既有源码,也有参数。**
**这里有个实践上的提醒:源码最好自己另存一份(文件或表里)。**
**因为 `SHOW CREATE` 出来的不一定是你当初写的那份——`sql_mode`、字符集都会被记下来,**
**而且一旦在服务器上改过,你本地那份就是旧的了。**
五、查「正在跑的过程」
--------------------------------------------------------------------
[教材原码 · 本沙箱不执行]
| SHOW PROCESSLIST;
教材原码,看当前有哪些连接在执行什么语句
[教材原码 · 本沙箱不执行]
| SELECT ID, TIME, STATE, INFO FROM information_schema.PROCESSLIST
| WHERE INFO LIKE '%p_list_cat%';
教材原码,筛出正在跑某个过程的连接
**过程跑起来之后,`PROCESSLIST` 里看到的是「里面正在执行的那条 SQL」,**
**不会是过程名——这一点常让人以为没在执行。**
**沙箱是单进程内嵌的,没有「连接列表」这个概念,这一节只能看原码。**
第一组只有一条 table 记录,没有 procedure、没有 function。
这就是「引擎里没有这类对象」最直接的证据。
第二组是复刻版的数据字典:一个字典存「函数本体、源码、注释、参数名」。
它对应 information_schema.ROUTINES,只是换了个存放的地方。
第三组打出名字、参数个数、注释——这三项正好是 SHOW PROCEDURE STATUS 的列。
第四组打出参数名和源码开头,对应 SHOW CREATE PROCEDURE。
参数是从函数签名里读的,源码是建的时候存下来的。
30 秒实验
- 再建一个「过程」,看清单里多一行、参数个数对不对。
- 把某个过程的源码字段清空,看第四组打印出什么。
- 给字典加一个「创建时间」字段,模拟
CREATED那一列。
常见误区
- 在沙箱里找
SHOW PROCEDURE STATUS,找不到就以为是自己写错了。 - 以为
PROCESSLIST里能看到过程名,其实显示的是里面那条 SQL。 - 只靠
SHOW CREATE找源码,改过一轮之后就分不清哪个是当前版本。
自测三问(点开对答案)
1. 为什么说「过程是可以被查询的对象」? —— 因为它存在数据字典里,能像表一样被列出、被导出、被备份,而不是只活在内存里的代码。 `information_schema.ROUTINES` 就是它的查询入口。 2. 三种查法里,哪一种最适合写进脚本? —— `information_schema.ROUTINES`。 它是普通查询,能加 `WHERE`、能 `JOIN`、能导出,前两种是给人看的固定格式。 3. `PROCESSLIST` 里为什么搜不到过程名? —— 因为显示的是过程内部正在执行的那条 SQL。想筛出来得按那条 SQL 的特征去 `LIKE`。查清了,下一篇讲怎么改:ALTER 只能改壳,逻辑必须删了重写。
- ☐ (本篇完,下一篇 14.4 修改存储过程和存储函数)