diff --git a/docs/basic/9.mysql_architecture.md b/docs/basic/9.mysql_architecture.md index ab968241e..8962d1afe 100644 --- a/docs/basic/9.mysql_architecture.md +++ b/docs/basic/9.mysql_architecture.md @@ -1121,6 +1121,32 @@ select count(1) from (select * from A where a>10)A1 Join (select * from B wh 正确性非常容易理解,如果一个改写的结果是错误的,这对业务的价值完全是负面的。完备性同样重要,它要求一个改写算法具有较好的通用性,不能只处理一些简单的场景,而不处理复杂的场景。通用性差对业务的价值是有限的。当然,我们很难把一个改写算法做到完全的完备。因为总有一些非常复杂的情形是很难处理的,强行改写可能会引入正确性问题。在实现一个改写算法的过程中,我们会在确保正确的前提下,尽可能的做到完备。 + +这个阶段,主要是对原来的语法树进行等价语义的重写,通常是根据预先定义好的规则来进行重写,优化掉一些无效或者无意义的操作。换句话说,有时候程序员写的 SQL 通常是结果导向的,并不专门针对执行去优化,而且,很多时候还会有意无意引入无意义的操作。 + +```SQL +SELECT + class.name AS class_name, + student.name AS student_name, + student.id AS student_id +FROM + class, student +WHERE + class.id = student.class_id AND + student.name = 'ZhangSan'; +``` + +上述语句返回这个学校所有叫 ZhangSan 的学生的姓名,学号,以及班级。 + +我们自下而上地来看。首先执行计划要求扫描全表 class 和表 student,然后对其进行 Join,join 条件是 class.id = student.class_id。 + +join 完之后,对于 tuple 进行 filter,filter 条件是 student.name = 'ZhangSan'。最后,对于 filter 后的 tuple,进行 projection,只有 3 个 column 作为输出 class.name, student.name 和 student.id。 + + +#### 投影下推 + +`Projections push down`。通过把用到的哪些 column 往下推送直到叶节点的 table scan,可以减少扫描后数据的大小,同时也可以提升扫描速度。 + #### 外连接消除 外连接消除的意义: diff --git "a/docs/dev/04.MySQL\350\277\236\350\241\250\346\237\245\350\257\242\347\256\227\346\263\225.md" "b/docs/dev/04.MySQL\350\277\236\350\241\250\346\237\245\350\257\242\347\256\227\346\263\225.md" index 073ed3b12..a05811d5f 100644 --- "a/docs/dev/04.MySQL\350\277\236\350\241\250\346\237\245\350\257\242\347\256\227\346\263\225.md" +++ "b/docs/dev/04.MySQL\350\277\236\350\241\250\346\237\245\350\257\242\347\256\227\346\263\225.md" @@ -1,15 +1,23 @@ # 连接查询 +为什么数据库需要支持 JOIN。这个问题,甚至可以再退一步到为什么数据库需要有多个表?其实答案很简单,上文都提到了:因为现实中的事物就是复杂,多样的。多个表之间的关系能方便地和现实世界的事物映射起来,并且这种映射更直观,更能够让人接受。就像面向对象编程一样,恐怕我们都不能想象如果面向对象编程只能创建一种类型的对象吧。 -写过或者学过 SQL 的人应该都知道 left join,知道 left join 的实现的效果,就是保留左表的全部信息,然后把右表往左表上拼接,如果拼不上就是 null。 -除了 left join 以外,还有 inner join、outer join、right join,这些不同的 join 能达到的什么样的效果,大家应该都了解了,如果不了解的可以看看网上的帖子或者随便一本 SQL 书都有讲的。 +除了方便映射实物,业务逻辑同样需要JOIN。举个例子,假设现在有个简单的电商系统有买家,卖家和订单三张表,数据科学家想要查询 2018 年,对于上海客户的销售额最高的前 3 位卖家信息。这么一个简单的查询其实就用到了每个表里的信息,需要从买家表里得到卖家信息,从买家表里得到地址是上海的买家 ID,然后对订单表以卖家 ID 做组队聚合,最后对销售总额进行排序并取前三 + + +写过或者学过 SQL 的人应该都知道 `left join`,知道 left join 的实现的效果,就是保留左表的全部信息,然后把右表往左表上拼接,如果拼不上就是 null。 + +除了 left join 以外,还有 `inner join`、`outer join`、`right join`,这些不同的 join 能达到的什么样的效果,大家应该都了解了,如果不了解的可以看看网上的帖子或者随便一本 SQL 书都有讲的。 尝试想一想,如果你是MySQL开发者,你会怎么做连表查询的,具体应该用什么算法实现。是一次性把两个表全部load到内存,再去进行关联匹配吗? + + + join 主要有 Nested Loop、Hash Join、Merge Join 这三种方式,我们这里只讲最普遍的,也是最好的理解的 Nested Loop join 。 Nested Loop join 翻译过来就是 **嵌套循环连接** 的意思,那什么又是嵌套循环呢?嵌套大家应该都能理解,就是一层套一层;那循环呢,你可以理解成是 for 循环。 @@ -126,7 +134,6 @@ select * from t1 straight_join t2 on (t1.a=t2.a); **BNL是基于块的嵌套循环连接 Block Nested Loop Join 算法(BNL)**,具体实现大概如下: - 把驱动表的数据读入到 **join_buffer** 中,然后扫描被驱动表,**把被驱动表每一行取出来跟 join_buffer 中的数据做对比。** ```sql diff --git "a/docs/postgresql/13.\346\267\261\345\205\245\347\220\206\350\247\243toast\346\212\200\346\234\257.md" "b/docs/postgresql/13.\346\267\261\345\205\245\347\220\206\350\247\243toast\346\212\200\346\234\257.md" new file mode 100644 index 000000000..0b17406e8 --- /dev/null +++ "b/docs/postgresql/13.\346\267\261\345\205\245\347\220\206\350\247\243toast\346\212\200\346\234\257.md" @@ -0,0 +1,8 @@ +# 什么是 Postgres TOAST? + +因为 `postgresql` 的 tuple(行数据)是存在在 `Page` 中的,`Page` 的大小默认为 8KB。postgresql 不允许 tuple 跨页存储,所以当一行数据的某个列数据过大时,比如 `text` 类型的数据,超过了单页的大小,那么 `postgresql` 会将它压缩,切分,并且存储在另外的位置。这种技术就是称为 Toast。 + +PostgreSQL Toast 使用是通过单个字段的大小来进行判断是否触发此机制的,比如一个字段,超过了`toast_tuple_threshold` 的阈值就会触发字段里面的值,要进行TOAST的工作流程,默认这个字段的值,大小要超过2KB,才会触发。 + +Postgres 的存储单位称为页,它们具有固定大小(默认为 8 kB)。固定页面大小为 Postgres 带来了许多优势,即数据管理简单、高效和一致性,但它也有一个缺点:某些数据值可能不适合该页面。 +