🛢️ 第4章 数据库操作
📄 一句话概括

看库有三种视角:有哪些、定义是什么、谁在吃磁盘。 SHOW DATABASES 是看列表,SHOW CREATE DATABASE 是看定义。 看占地得查 information_schema,那边才有字节数。

📝 本章和前面几章的关系

上一篇建库,这一篇看它。 这一篇的三条语句是日常最常用的:接手一个陌生实例,先列库,再看定义,再看占地。 顺序别反:先知道有哪些,再挑重点看。 和第 12 章的关系:查表的空间占用也是同一套办法,只是换成 TABLES。

一、视角一:有哪些

SHOW DATABASES; 列出全部库名,一行一个。 要过滤就加 LIKE:SHOW DATABASES LIKE 'db%';。 它背后就是一条查询:SELECT SCHEMA_NAME FROM information_schema.SCHEMATA; 知道这一点,你就明白为什么它「不用选库也能跑」——它查的是全局字典。

语句 返回什么 能过滤吗
SHOW DATABASES 全部库名 只能加 LIKE
SHOW DATABASES LIKE 'db%' 匹配的库名 能,但只支持简单通配
SELECT ... FROM information_schema.SCHEMATA 库名加字符集等列 能,随便写 WHERE

第三行才是「高手写法」:拿到完整两列(库名、默认字符集),一次看全。

二、视角二:定义是什么

SHOW CREATE DATABASE 库名; 会把「重建这个库需要的那句话」打出来。 它包含两件事:字符集、校对规则。 这一句接手陌生库时必跑。 因为「这个库到底是不是 utf8mb4」,光看库名看不出来。 它输出里那串 /*!40100 ... */ 是版本注释:MySQL 5 以上的版本才执行这段。 这是为了让同一份脚本能在老版本上跑也不报错——一种兼容写法,不是乱码。

三、视角三:谁在吃磁盘

SHOW 系列不告诉你字节数,那得查 information_schema.TABLES。

想知道的 查哪一列
数据占多少 DATA_LENGTH
索引占多少 INDEX_LENGTH
大概多少行 TABLE_ROWS(统计值,不是精确值)
这张表属于哪个库 TABLE_SCHEMA

TABLE_ROWS 那一行要注意:它是统计值,InnoDB 给的是估算。 要精确行数只能 SELECT COUNT(*),大表上还很慢。 第三个容易误解的是 DATA_LENGTH:它包含碎片空间。 删了很多行之后,这个数不会跟着变小——得 OPTIMIZE TABLE 才回收。

四、三条语句怎么配合用

接手一个陌生实例,按这个顺序走,十分钟能摸清家底。

步 查什么 为什么
1 SHOW DATABASES 先知道有哪些,别漏了业务库
2 SELECT ... FROM SCHEMATA 一次看到库名和默认字符集
3 按 DATA_LENGTH 排个序 找出真正占空间的那几个
4 对大的库跑 SHOW CREATE DATABASE 确认字符集,避免后面踩坑

第四步别省:一个大库如果是三字节的 utf8,后面每一次「存 emoji 报错」都跟它有关。

五、动手 Demo:看库的三种视角:列表、定义、占地

这一课把三种视角各跑一遍。 模型里没有 information_schema,所以占地那一项直接量目录大小。 真机上对应的是查 DATA_LENGTH 和 INDEX_LENGTH。

cat = Catalog(DATA)
for n in ("db_database28", "db_shop", "db_blog"):
    cat.create(n)

# 视角一:有哪些
print(cat.databases())

# 视角二:定义是什么
for n in cat.databases():
    print("mysql> SHOW CREATE DATABASE", n)
    print(cat.show_create(n))

# 视角三:谁在吃磁盘
rows = [[n, len(cat.tables(n)), cat.size(n)] for n in cat.databases()]
rows.sort(key=lambda r: -r[2])
for r in rows:
    print(r)

实跑输出:

--------------------------------------------------------------------
第十九课:看库的三种视角:列表、定义、占地
--------------------------------------------------------------------

  **教材 4.3 节讲「查看数据库」,其实有三种看法,用途完全不同。**
  **看列表是「有哪些」,看定义是「字符集是什么」,看占地是「谁在吃磁盘」。**

  一、有哪些:SHOW DATABASES
  --------------------------------------------------------------------

  [教材原码 · 本沙箱不执行]
  | SHOW DATABASES;
  | SHOW DATABASES LIKE 'db%';
  | SELECT SCHEMA_NAME FROM information_schema.SCHEMATA;
    (全部、按模式过滤、以及它背后那条真正的查询)

  **真跑一下等价的:列出目录。**

  库名
  -------------
  db_blog
  db_database28
  db_shop
  **MySQL 会多出四个系统库,这里没有——这正是模型和真机的差别。**

  二、定义是什么:SHOW CREATE DATABASE
  --------------------------------------------------------------------
  mysql> SHOW CREATE DATABASE db_blog
  CREATE DATABASE `db_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE
      utf8mb4_0900_ai_ci */
  mysql> SHOW CREATE DATABASE db_database28
  CREATE DATABASE `db_database28` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE
      utf8mb4_0900_ai_ci */
  mysql> SHOW CREATE DATABASE db_shop
  CREATE DATABASE `db_shop` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE
      utf8mb4_0900_ai_ci */
  **这一句最有用:它把「这个库用什么字符集、什么校对规则」一次说清。**
  **接手一个陌生的库,先跑这一句。**

  三、谁在吃磁盘:按大小排
  --------------------------------------------------------------------

  库名           表数  字节数
  ---------------------------
  db_shop        1     49207
  db_blog        0     55
  db_database28  0     55
  **三个库都是刚建的,只有一个灌了 2000 行,大小立刻差出两个数量级。**
  **所以「库多不多」和「磁盘够不够」是两件事。**
  **MySQL 上要看这个得查 `information_schema.TABLES` 的 `DATA_LENGTH` 和 `INDEX_LENGTH` 两列。**

第一段只有三行输出,就是三个库名。 MySQL 上会多出四个系统库,这里没有——这正是模型和真机的差别。 第二段每个库打一行 CREATE DATABASE,长得很像,只有库名不同。 因为三个库都是默认字符集建的。 如果其中一个是 5.7 时代建的,这一行就会露出 utf8 而不是 utf8mb4。 第三段按大小排序,三个库差了两个数量级。 原因只有一个:那个灌了 2000 行的库有真实数据,另外两个是空壳。 最后我补了一句: MySQL 上要看占地得查 information_schema.TABLES 的 DATA_LENGTH 和 INDEX_LENGTH。 模型里是量目录,真机上是查字典,思路一样。

30 秒实验

  1. 把 SHOW DATABASES LIKE 'db%' 的条件改成 LIKE '%shop%',想想结果是什么。 只有 db_shop 命中。 LIKE 里 % 是任意个字符,位置决定匹配方式。
  2. 在 Demo 里给 db_blog 也灌 1000 行,再排一次序。两个库的大小会接近,因为它们的数据量接近。 库名和大小没关系,里面的东西才有关系。
  3. 想一想:SHOW CREATE DATABASE 输出的那串 /*!40100 ... */ 是注释吗? 是「版本注释」:MySQL 5 以上才执行,以下当注释忽略。 这是为了让一份脚本兼容多个版本,不是写错了。

常见误区

  1. 「SHOW DATABASES 只给库名,看不到字符集。」 对,所以要看字符集得用 SHOW CREATE DATABASE,或者直接查 information_schema.SCHEMATA。
  2. 「TABLE_ROWS 是精确行数。」 是估算值,InnoDB 不会为了回答这个问题去数一遍。要精确只能 SELECT COUNT(*)。
  3. 「删了数据,DATA_LENGTH 会变小。」 不会,它包含碎片空间。 要回收得 OPTIMIZE TABLE,那是个重活。
自测三问(点开对答案) 1. `SHOW DATABASES` 背后查的是什么? —— **`information_schema.SCHEMATA`。** **所以它不用选库也能跑——查的是全局字典。** 2. 想知道一个库的字符集,跑哪条语句最快? —— **`SHOW CREATE DATABASE 库名;`** **一行输出里就带着字符集和校对规则。** 3. 要看一张表占多少空间,查哪两列? —— **`DATA_LENGTH` 和 `INDEX_LENGTH`。** **一个管数据,一个管索引,加起来才是这张表的总开销。**

下一篇讲 USE:它改的是「这条连接」的状态,不是「数据库」的状态。 搞清这一点,才明白为什么忘了它会报 1046。

相关笔记