博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
程序员与笛卡尔积
阅读量:6166 次
发布时间:2019-06-21

本文共 3652 字,大约阅读时间需要 12 分钟。

SQL与笛卡尔积

首先,先简单解释一下笛卡尔积。

现在,我们有两个集合A和B。

A = {0,1}     B = {2,3,4}复制代码

集合 A×B 和 B×A的结果集就可以分别表示为以下这种形式:

A×B = {(0,2),(1,2),(0,3),(1,3),(0,4),(1,4)};B×A = {(2,0),(2,1),(3,0),(3,1),(4,0),(4,1)};复制代码

以上A×B和B×A的结果就可以叫做两个集合相乘的笛卡尔积

从以上的数据分析我们可以得出以下两点结论:

  1. 两个集合相乘,不满足交换率,既 A×B ≠ B×A;

  2. A集合和B集合相乘,包含了集合A中元素和集合B中元素按顺序结合的所有的可能性。既两个集合相乘得到的新集合的元素个数是 A集合的元素个数 × B集合的元素个数;

  3. 其实和高中数学里的排列很类似,不过排列里含有(2,0)、(0,2),而笛卡尔积只有其中一个:AxB则是(0,2),BxA则是(2,0)。

数据库表连接数据行匹配时所遵循的算法就是以上提到的笛卡尔积,表与表之间的连接可以看成是在做乘法运算。

比如现在数据库中有两张表,student表和 student_subject表,如下所示:

我们执行以下的sql语句,只是纯粹的进行表连接。

SELECT * from student JOIN student_subject;SELECT * from student_subject JOIN student;复制代码

看一下执行结果:

从执行结果上来看,结果符合我们以上提出的两点结论;

以第一条sql语句为例我们来看一下他的执行流程,

  1. from语句把student表 和 student_subject表从数据库文件加载到内存中。

  2. join语句相当于对两张表做了乘法运算,把student表中的每一行记录按照顺序和student_subject表中记录依次匹配。

  3. 匹配完成后,我们得到了一张有 (student中记录数 × student_subject表中记录数)条的临时表。 在内存中形成的临时表如表1.0所示。我们又把内存中表1.0所示的表称为笛卡尔积表

针对以上的理论,我们提出一个问题,难道表连接的时候都要先形成一张笛卡尔积表吗?

如果两张表的数据量都比较大的话,那样就会占用很大的内存空间这显然是不合理的。所以,我们在进行表连接查询的时候一般都会使用JOIN xxx ON xxx的语法,ON语句的执行是在JOIN语句之前的,也就是说两张表数据行之间进行匹配的时候,会先判断数据行是否符合ON语句后面的条件再决定是否JOIN

  因此,有一个显而易见的SQL优化的方案是,当两张表的数据量比较大,又需要连接查询时,应该使用 FROM table1 JOIN table2 ON xxx的语法,避免使用 FROM table1,table2 WHERE xxx 的语法,因为后者会在内存中先生成一张数据量比较大的笛卡尔积表,增加了内存的开销。

根据上一篇博客( ),及本篇博客的分析,我们可以总结出一条查询sql语句的执行流程。

1. From 2. ON 3. JOIN 4. WHERE 5. GROUP BY 6. SELECT 7. HAVING 8. ORDER BY 9. LIMIT复制代码

最后,针对两张数据库表连接的底层实现,我用java代码模拟了一下,感兴趣的可以看一下,能够帮助我们理解:

package com.opensource.util;import java.util.Arrays;public class DecareProduct {        public static void main(String[] args) {                //使用二维数组,模拟student表        String[][] student ={                {
"0","jsonp"}, {
"1","alice"} }; //使用二维数组,模拟student_subject表 String[][] student_subject2 ={ {
"0","0","语文"}, {
"1","0","数学"} }; //模拟 SELECT * from student JOIN student_subject; String[][] resultTowArray1 = getTwoDimensionArray(student,student_subject2); //模拟 SELECT * from student_subject JOIN student; String[][] resultTowArray2 = getTwoDimensionArray(student_subject2,student); int length1 = resultTowArray1.length; for (int i = 0; i

执行结果:

几个join的笛卡尔积:

  • 两表直接连接,笛卡尔积的结果数量是两表的数据量相乘
  • 带where/on条件id相等的笛卡尔积和inner join结果相同,但是inner join效率快一点
  • left join:TEST_A表的ID为空时拼接TEST_B表的内容为空,
  • right join则相反
  • full join:等于left join和right join的并集

因此如果程序的确需要多表联合查询,尽量两两连接,并通过where或on或inner join缩小结果集,再将结果集对其他表继续连接……

JavaIO的装饰模式与笛卡尔积

在学习 java.io 包的时候,InputStream 那一群类很让人反感,子类繁多就不用说,使用起来非常奇怪,因为它使用了装饰模式……

假设我们想以缓存的方式从文件中读取字节流,一般常见的操作总是:先创建一个FileInputStream,然后把这个FileInputStream放入BufferedInputStream构造函数中去创建BufferedInputStream。完成这些工作后才能开始读取文件:

try (FileInputStream fis = new FileInputStream("c:/a.txt");	     BufferedInputStream bis = new BufferedInputStream(fis)) {		byte[] buffer = new byte[1024];		int len;		StringBuilder result = new StringBuilder();		while ((len = bis.read(buffer)) != -1) {			result.append(new String(buffer, 0, len));		}            	} catch (IOException e) {		//handle	}复制代码

为什么 sun 不能直接创建以缓存方式从文件中读取数据的输入流类呢?

或者说为什么InputStream选择装饰者模式,而非直接继承的方法来扩展,也就是装饰者模式VS继承。

为了回答这个问题,就以InputStream与FilterInputStream两者组合,如果我用了继承,看看我们的类图是什么样的:

似曾相识,我们再看一下:

InputStream:[ FileInputStreamByteArrayInput StreamSequenceInputStreamObjectInputreamPipedInputStreamStringBufferInputStream……还包括其他二方、三方继承InputStream自实现的InputStream子类,目前至少有两百多个各种实现]

FilterInputStream(它也继承自InputStream):[BufferedInputStreamDataInputStreamPushbackInputStream……]

两者假设进行任意组合,即可构成一个所谓的输出流类,那么这种输出流类的数量将是一个笛卡儿积,即爆炸增长,同时InputStream内部还可以进行互相组合。

而如果采用装饰模式,具体你们怎么搭配我不关心,只需要套个装饰,即变成了一个新的功能的输出流类

SQL与笛卡尔积 转自:

转载地址:http://rluba.baihongyu.com/

你可能感兴趣的文章
MFC控件的SubclassDlgItem
查看>>
如何避免历史回退到登录页面
查看>>
《图解HTTP》1~53Page Web网络基础 HTTP协议 HTTP报文内的HTTP信息
查看>>
unix环境高级编程-高级IO(2)
查看>>
树莓派是如何免疫 Meltdown 和 Spectre 漏洞的
查看>>
雅虎瓦片地图切片问题
查看>>
HTML 邮件链接,超链接发邮件
查看>>
HDU 5524:Subtrees
查看>>
手机端userAgent
查看>>
pip安装Mysql-python报错EnvironmentError: mysql_config not found
查看>>
http协议组成(请求状态码)
查看>>
怎样成为一个高手观后感
查看>>
[转]VC预处理指令与宏定义的妙用
查看>>
MySql操作
查看>>
python 解析 XML文件
查看>>
MySQL 文件导入出错
查看>>
java相关
查看>>
由一个异常开始思考springmvc参数解析
查看>>
向上扩展型SSD 将可满足向外扩展需求
查看>>
虚机不能启动的特例思考
查看>>