查询可分为两种,逻辑查询处理表示执行查询应该产生什么样的结果,而物理查询代表MySQL数据库是如何得到该结
果的。

逻辑查询处理

SQL中,第一个被处理的子句总是FROM子句。下面展示了逻辑查询处理的顺序以及步骤的序号。

(8) SELECT (9) DISTINCT<select_list>
(1) FROM <left_table>
(3)<join_type> JOIN <right_table>
(2)    ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH {CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <order_by_list>
(11) LIMIT <limit_number>

一共有11个步骤,每个操作都会产生一张虚拟表,该虚拟表作为一个处理的输入。
但只有最后一步生成的虚拟表才会返回给客户。

接着分析各个阶段:
1)FROM : 对FROM表子句的左表<left_table>和右表<right_table>执行笛卡尔积,产生虚拟表VT1
2)ON : 对虚拟表VT1应用ON筛选,只有符合<join_condition>的行才被插入到虚拟表VT2中
3)JOIN:如果指定了OUTER JOIN,那么保留表中未匹配的行作为外部行添加到虚拟表VT2中,产生虚拟表VT3
4)WHERE:对虚拟表VT3应用WHERE过滤条件,只有符合<where_condition>的记录才被插入虚拟表VT4中
5)GROUP BY:根据GROUP BY子句中的列,对VT4中的记录进行分组操作,产生VT5
6)CUBE|ROLLUP:对VT5进行CUBE或ROLLUP操作,产生VT6
7)HAVING:对VT6应用HAVING过滤器,只有符合<having_condition>的记录才被插入到VT7中
8)SELECT:第二次执行SELECT操作,选择指定的列,插入到虚拟表VT8中
9)DISTINCT:去除重复数据,产生虚拟表VT9
10)ORDER BY:将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10
11)LIMIT:去除指定行的记录,产生虚拟表VT11,并返回给查询用户

with rollup 通常和group by 语句一起使用,对group by的分组进行汇总。
rollup是cube的一种特殊情况,和rollup一样,cube也是一种对数据的聚合操作。但是rollup只在层次上对数据进行聚合,而cube对所有的维度进行聚合

下面通过一个查询示例来描述上面逻辑处理的11个阶段:

CREATE TABLE customers
(
customer_id VARCHAR(10)NOT NULL,
city VARCHAR(10)NOT NULL,
PRIMARY KEY(customer_id)
)ENGINE=INNODB;INSERT INTO customers SELECT'163','HangZhou';
INSERT INTO customers SELECT'9you','ShangHai';
INSERT INTO customers SELECT'TX','HangZhou';
INSERT INTO customers SELECT'baidu','HangZhou';CREATE TABLE orders
(
order_id INT NOT NULL AUTO_INCREMENT,
customer_id VARCHAR(10),
PRIMARY KEY(order_id)
)ENGINE=INNODB;INSERT INTO orders SELECT NULL,'163';
INSERT INTO orders SELECT NULL,'163';
INSERT INTO orders SELECT NULL,'9you';
INSERT INTO orders SELECT NULL,'9you';
INSERT INTO orders SELECT NULL,'9you';
INSERT INTO orders SELECT NULL,'TX';
INSERT INTO orders SELECT NULL, NULL;

通过如下语句来查询来自杭州且订单数少于2的客户,并且查询出他们的订单数量,
查询结果按订单数从小到大排序:

SELECT c.customer_id,count(o.order_id) as total_orders FROM customers c
LEFT JOIN orders o on o.customer_id = c.customer_id
where c.city = 'HangZhou'
GROUP BY c.customer_id HAVING COUNT(o.order_id) < 2
ORDER BY total_orders;

执行笛卡尔积

第一步需要做的是对FROM子句前后的两张表执行笛卡尔积操作,也称作交叉连接,生成虚拟表VT1。
VT1的行数为两张表的行数之积。VT1的列由源表定义。

mysql> select * from customers,orders;
+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | HangZhou |        1 | 163         |
| 9you        | ShangHai |        1 | 163         |
| baidu       | HangZhou |        1 | 163         |
| TX          | HangZhou |        1 | 163         |
| 163         | HangZhou |        2 | 163         |
| 9you        | ShangHai |        2 | 163         |
| baidu       | HangZhou |        2 | 163         |
| TX          | HangZhou |        2 | 163         |
| 163         | HangZhou |        3 | 9you        |
| 9you        | ShangHai |        3 | 9you        |
| baidu       | HangZhou |        3 | 9you        |
| TX          | HangZhou |        3 | 9you        |
| 163         | HangZhou |        4 | 9you        |
| 9you        | ShangHai |        4 | 9you        |
| baidu       | HangZhou |        4 | 9you        |
| TX          | HangZhou |        4 | 9you        |
| 163         | HangZhou |        5 | 9you        |
| 9you        | ShangHai |        5 | 9you        |
| baidu       | HangZhou |        5 | 9you        |
| TX          | HangZhou |        5 | 9you        |
| 163         | HangZhou |        6 | TX          |
| 9you        | ShangHai |        6 | TX          |
| baidu       | HangZhou |        6 | TX          |
| TX          | HangZhou |        6 | TX          |
| 163         | HangZhou |        7 | NULL        |
| 9you        | ShangHai |        7 | NULL        |
| baidu       | HangZhou |        7 | NULL        |
| TX          | HangZhou |        7 | NULL        |
+-------------+----------+----------+-------------+
28 rows in set (0.00 sec)

应用ON过滤器

SELECT查询一共有3个过滤过程,分别是ON、WHERE、
HAVING。ON是最先执行的过滤过程。根据上一小节产生的虚拟表
VT1,过滤条件为:

on o.customer_id = c.customer_id

在关系数据库中起逻辑表达式作用的除了TRUEFALSE外,还有一种称为
三值逻辑的表达式。因为,在关系数据库中,NULL的比较很特殊:


mysql> select 1=NULL\G;
*************************** 1. row ***************************
1=NULL: NULL
1 row in set (0.00 sec)mysql> select NULL=NULL\G;
*************************** 1. row ***************************
NULL=NULL: NULL
1 row in set (0.00 sec)

第一个NULL值的比较返回的是NULL而不是0,第二个比较返回的仍然是NULL而不是1,。
对于比较返回值为NULL的情况,应将其视为UNKNOWN,即未知的。因为在某些情况下,
NULL返回值可能代表1,即NULL等于NULL,而有时NULL返回值可能代表0。

对于在ON过滤条件下的NULL值比较,此时的比较结果为UNKNOWN,却被视为FALSE来进行处理,
即两个NULL并不相同。

但在下面两种情况下两个NULL值的比较是相等的:

  • GROUP BY子句把所有NULL值分到同一组
  • ORDER BY子句把所有NULL值排列在一起

来看一个例子:

CREATE TABLE t(a CHAR(5))ENGINE=INNODB;
INSERT INTO t SELECT'a';
INSERT INTO t SELECT NULL;
INSERT INTO t SELECT'b';
INSERT INTO t SELECT'c';
INSERT INTO t SELECT NULL;

对列a进行ORDER BY操作:

mysql> SELECT * FROM t ORDER BY a;
+------+
| a    |
+------+
| NULL |
| NULL |
| a    |
| b    |
| c    |
+------+
5 rows in set (0.00 sec)

在进行分组:

mysql> SELECT a,COUNT(1) FROM t GROUP BY a;
+------+----------+
| a    | COUNT(1) |
+------+----------+
| NULL |        2 |
| a    |        1 |
| b    |        1 |
| c    |        1 |
+------+----------+
4 rows in set (0.00 sec)

对于ORDER BY的SQL查询语句,返回结果将两个NULL值并列在一起返回。而对于
分组查询语句,返回NULL值的有两条记录。

因此产生虚拟表VT2时,会增加一个额外的列来表示ON过滤条件的返回值,
返回值有TRUEFALSEUNKNOWN

+-------------+-------------+----------+----------+-------------+
|    Match    | customer_id | city     | order_id | customer_id |
+-------------+-------------+----------+----------+-------------+
| TRUE        | 163         | HangZhou |        1 | 163         |
| FALSE       | 9you        | ShangHai |        1 | 163         |
| FALSE       | baidu       | HangZhou |        1 | 163         |
| FALSE       | TX          | HangZhou |        1 | 163         |
| TRUE        | 163         | HangZhou |        2 | 163         |
| FALSE       | 9you        | ShangHai |        2 | 163         |
| FALSE       | baidu       | HangZhou |        2 | 163         |
| FALSE       | TX          | HangZhou |        2 | 163         |
| FALSE       | 163         | HangZhou |        3 | 9you        |
| TRUE        | 9you        | ShangHai |        3 | 9you        |
| FALSE       | baidu       | HangZhou |        3 | 9you        |
| FALSE       | TX          | HangZhou |        3 | 9you        |
| FALSE       | 163         | HangZhou |        4 | 9you        |
| TRUE        | 9you        | ShangHai |        4 | 9you        |
| FALSE       | baidu       | HangZhou |        4 | 9you        |
| FALSE       | TX          | HangZhou |        4 | 9you        |
| FALSE       | 163         | HangZhou |        5 | 9you        |
| TRUE        | 9you        | ShangHai |        5 | 9you        |
| FALSE       | baidu       | HangZhou |        5 | 9you        |
| FALSE       | TX          | HangZhou |        5 | 9you        |
| FALSE       | 163         | HangZhou |        6 | TX          |
| FALSE       | 9you        | ShangHai |        6 | TX          |
| FALSE       | baidu       | HangZhou |        6 | TX          |
| TRUE        | TX          | HangZhou |        6 | TX          |
| UNKNOWN     | 163         | HangZhou |        7 | NULL        |
| UNKNOWN     | 9you        | ShangHai |        7 | NULL        |
| UNKNOWN     | baidu       | HangZhou |        7 | NULL        |
| UNKNOWN     | TX          | HangZhou |        7 | NULL        |
+-------------+-------------+----------+----------+-------------+

取出比较值为TRUE的记录,产生虚拟表VT2,结果如下所示:

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | HangZhou |        1 | 163         |
| 163         | HangZhou |        2 | 163         |
| 9you        | ShangHai |        3 | 9you        |
| 9you        | ShangHai |        4 | 9you        |
| 9you        | ShangHai |        5 | 9you        |
| TX          | HangZhou |        6 | TX          |
+-------------+----------+----------+-------------+

添加外部行

这一步只有在连接类型为OUTER JOIN时才发生,如LEFT
OUTER JOIN、RIGHT OUTER JOIN、FULL OUTER JOIN。虽然在
大多数时候我们可以省略OUTER关键字,但OUTER代表的就是外部
行。LEFT OUTER JOIN把左表记为保留表,RIGHT OUTER JOIN把
右表记为保留表,FULL OUTER JOIN把左右表都记为保留表。添加
外部行的工作就是在VT2表的基础上添加保留表中被过滤条件过滤掉
的数据,非保留表中的数据被赋予NULL值,最后生成虚拟表VT3

mysql> SELECT * FROM customers c   LEFT JOIN orders o on o.customer_id = c.customer_id;+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | HangZhou |        1 | 163         |
| 163         | HangZhou |        2 | 163         |
| 9you        | ShangHai |        3 | 9you        |
| 9you        | ShangHai |        4 | 9you        |
| 9you        | ShangHai |        5 | 9you        |
| TX          | HangZhou |        6 | TX          |
| baidu       | HangZhou |     NULL | NULL        |
+-------------+----------+----------+-------------+

顾客baidu在VT2表中由于没有订单而被过滤,因此baidu作为外部行
被添加到虚拟表VT2中,将非保留表中的数据赋值为NULL。

应用WHERE过滤器

对上一步骤产生的虚拟表进行WHERE条件过滤,只有符合<where_condition>的记录才会输出到虚拟表VT4中。

在当前应用WHERE过滤器时,有两种过滤是不被允许的:

  • 由于数据还没有分组,因此现在还不能使用where_condition=MIN(col)这类对统计的过滤
  • 由于没有进行列的选取操作,因此在SELECT中使用列的别名也是不被允许的,如SELECT city as c FROM t WHERE c = 'ShangHai'是不允许出现的

首先看一个在WHERE过滤条件中使用分组过滤查询导致出错的例子:

mysql> SELECT customer_id,COUNT(customer_id) FROM orders WHERE COUNT(customer_id) < 2;
ERROR 1111 (HY000): Invalid use of group function

可以看到MySQL数据库提示错误的使用了分组函数。接下来看一个列别名使用出错的例子:

mysql> SELECT order_id AS o,customer_id AS c FROM orders WHERE c = '163';
ERROR 1054 (42S22): Unknown column 'c' in 'where clause'

因为在当前的步骤中还未进行SELECT选取列名的操作,所以此时的列别名是不被支持的。

应用WHERE过滤器:WHERE c.city = 'HangZhou',得到的虚拟表VT4如下所示:

mysql> SELECT * FROM customers c   LEFT JOIN orders o on o.customer_id = c.customer_id WHERE c.city = 'HangZhou';
+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | HangZhou |        1 | 163         |
| 163         | HangZhou |        2 | 163         |
| TX          | HangZhou |        6 | TX          |
| baidu       | HangZhou |     NULL | NULL        |
+-------------+----------+----------+-------------+
4 rows in set (0.01 sec)

WHERE过滤器中进行的过滤和在ON过滤器中进行的过滤是有所不同的。对于OUTER JOIN中的过滤,在ON过滤器过滤完之后还会添加保留表中被ON条件过滤到的记录(比如这里的baidu),而WHERE条件中被过滤掉的记录则是永久的过滤。在INNTER JOIN中两者是没有差别的,因为没有添加外部行的操作。

mysql> SELECT * FROM customers c LEFT JOIN orders o ON c.customer_id = o.customer_id AND c.city = 'HangZhou';
+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | HangZhou |        1 | 163         |
| 163         | HangZhou |        2 | 163         |
| TX          | HangZhou |        6 | TX          |
| 9you        | ShangHai |     NULL | NULL        |
| baidu       | HangZhou |     NULL | NULL        |
+-------------+----------+----------+-------------+
5 rows in set (0.00 sec)

对比上面两个表可以发现,customer_id为9you的记录被添加到后者的查询结果汇总。因为ON过滤条件虽然过滤掉了city不等于"HangZhou"的记录,但是由于是OUTER JOIN,因此会对保留表中被排除的记录进行再次的添加操作。

分组

在本步骤中根据指定的列对上个步骤中产生的虚拟表进行分组,得到VT5:
GROUP BY c.customer_id

mysql> SELECT * FROM customers c   LEFT JOIN orders o on o.customer_id = c.customer_id WHERE c.city = 'HangZhou' GROUP BY c.customer_id;
+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | HangZhou |        1 | 163         |
| baidu       | HangZhou |     NULL | NULL        |
| TX          | HangZhou |        6 | TX          |
+-------------+----------+----------+-------------+
3 rows in set (0.00 sec)

GROUP BY阶段,数据库认为两个NULL值是相等的,因此会将NULL值分到同一个分组中。

应用ROLLUP或CUBE

我们的查询未用到ROLLUP,跳过本步骤。

应用HAVING过滤器

在该步骤中对于上一步产生的虚拟表应用HAVING过滤器,
HAVING是对分组条件进行过滤的筛选器。对于示例的查询语句,其
分组条件为:
HAVING count(o.order_id) < 2

mysql> SELECT * FROM customers as c-> LEFT JOIN orders as o ON c.customer_id=o.customer_id WHERE c.city='HangZhou'-> GROUP BY c.customer_id HAVING COUNT(o.order_id) < 2;
+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| baidu       | HangZhou |     NULL | NULL        |
| TX          | HangZhou |        6 | TX          |
+-------------+----------+----------+-------------+
2 rows in set (0.00 sec)

处理SELECT列表

虽然SELECT是查询中最先被指定的部分,但是直到步骤8)时
才真正进行处理。在这一步中,将SELECT中指定的列从上一步产生
的虚拟表中选出。

列的别名不能在SELECT中的其他别名表达式中使用。
因此对于下列查询MySQL数据库会抛出错误提示:

mysql> SELECT order_id AS o,o+1 AS n FROM orders;
ERROR 1054 (42S22): Unknown column 'o' in 'field list'
mysql> SELECT order_id AS o,o+1  FROM orders;
ERROR 1054 (42S22): Unknown column 'o' in 'field list'

对于示例的SQL查询,其SELECT部分为:

SELECT c.customer_id,count(o.customer_id) AS total_orders

最后计算得到的虚拟表VT7如下:

mysql> SELECT c.customer_id,count(o.customer_id) AS total_orders FROM customers as c-> LEFT JOIN orders as o ON c.customer_id=o.customer_id WHERE c.city='HangZhou'-> GROUP BY c.customer_id HAVING COUNT(o.order_id) < 2;
+-------------+--------------+
| customer_id | total_orders |
+-------------+--------------+
| baidu       |            0 |
| TX          |            1 |
+-------------+--------------+
2 rows in set (0.00 sec)

应用DISTINCT子句

如果在查询中指定了DISTINCT子句,则会创建一张内存临时表
(如果内存中存放不下就放到磁盘上)。这张内存临时表的表结构和
上一步产生的虚拟表一样,不同的是对进行DISTINCT操作的列增加
了一个唯一索引,以此来去除重复数据。

由于在这个SQL查询中未指定DISTINCT,因此跳过本步骤。另
外,对于使用了GROUP BY的查询,再使用DISTINCT是多余的,因
为已经进行分组,不会移除任何行。

应用ORDER BY子句

根据ORDER BY子句中指定的列对上一步输出的虚拟表进行排
列,返回新的虚拟表。还可以在ORDER BY子句中指定SELECT列表
中列的序列号,如下面的语句:

SELECT order_id, customer_id
FROM orders
ORDER BY 2,1;

等同于

SELECT order_id, customer_id
FROM orders
ORDER BY customer_id,order_id;

除非用户对网络传输要求很高,作为一种节省网络传输字节的方法,否则不推荐使用

对于我们的示例,ORDER BY子句为:
ORDER BY total_orders DESC;

mysql> SELECT c.customer_id,count(o.customer_id) AS total_orders FROM customers as c-> LEFT JOIN orders as o ON c.customer_id=o.customer_id WHERE c.city='HangZhou'-> GROUP BY c.customer_id HAVING COUNT(o.order_id) < 2 ORDER BY total_orders DESC;
+-------------+--------------+
| customer_id | total_orders |
+-------------+--------------+
| TX          |            1 |
| baidu       |            0 |
+-------------+--------------+
2 rows in set (0.00 sec)

数据库中常见的查询操作其实对应的是集合的某些运算:
选择、投影、连接、并、交、差、除。最终的结果虽然是以一张二维
表的方式呈现在用户面前,但是从数据库内部来看是一系列的集合操
作。因此,对于表中的记录,用户需要以集合的思想来理解。
不要为表中的行假定任何特定的顺序。如果需要有序输出行记录,
则必须使用ORDER BY子句

排序需要成本,可以通过变量来查看数据库的排序操作:

mysql> SELECT*FROM orders ORDER BY customer_id\G;
*************************** 1. row ***************************order_id: 7
customer_id: NULL
*************************** 2. row ***************************order_id: 1
customer_id: 163
*************************** 3. row ***************************order_id: 2
customer_id: 163
*************************** 4. row ***************************order_id: 3
customer_id: 9you
*************************** 5. row ***************************order_id: 4
customer_id: 9you
*************************** 6. row ***************************order_id: 5
customer_id: 9you
*************************** 7. row ***************************order_id: 6
customer_id: TX
7 rows in set (0.00 sec)mysql> SHOW STATUS LIKE '%sort%'\G;
*************************** 1. row ***************************
Variable_name: Sort_merge_passesValue: 0
*************************** 2. row ***************************
Variable_name: Sort_rangeValue: 0
*************************** 3. row ***************************
Variable_name: Sort_rowsValue: 7
*************************** 4. row ***************************
Variable_name: Sort_scanValue: 1
4 rows in set (0.00 sec)

在上面这个例子中可以看到,SQL语句对customer_id进行了
ORDER BY排序操作,而在customer_id列上没有索引,因此需要进行
排序操作。在当前会话的状态中,Sort_scan为1,Sort_rows为7,表示
进行了一次排序扫描操作,共排序了7条记录。在实际的生产环境
中,需要观察这些变量,判断是否可以通过添加索引来避免额外的排
序开销。

前面已经提及,在ORDER BY子句中,NULL值被认为是相同的
值,会将其排序在一起。在MySQL数据库中,NULL值在升序过程中
总是首先被选出,即NULL值在ORDER BY子句中被视为最小值

LIMIT子句

在该步骤中应用LIMIT子句,从上一步骤的虚拟表中选出从指定
位置开始的指定行数据。对于没有应用ORDER BYLIMIT子句,结
果同样可能是无序的,因此LIMIT子句通常和ORDER BY子句一起使
用。

MySQL数据库的LIMIT支持如下形式的选择:
LIMIT n,m

表示从第n条记录开始选择m条记录。

物理查询处理

在MySQL数据库层有Parser和Optimizer两个组
件。Parser的工作就是分析SQL语句,而Optimizer的工作就是对这个
SQL语句进行优化,选择一条最优的路径来选取数据。

如果表上建有索引,那么优化器就会判断SQL语句是否可以利用
该索引来进行优化。如果没有可以利用的索引,可能整个SQL语句的
执行代价非常大。

CREATE TABLE x(a int) ENGINE=INNODB;
CREATE TABLE y(a int) ENGINE=INNODB;
CALL pFastCreateNums(500000);
INSERT INTO x SELECT * FROM nums LIMIT 100000;
INSERT INTO y SELECT * FROM nums LIMIT 180000;

通过数字辅助表生成了10万行数据表x和18行数据表y。表x和y尚都没有索引,
,因此最终SQL解析器解析的执行结果为逻辑处理
的步骤,也就是按照上一节中分析的,总共经过11个步骤来进行数据
的查询。最先根据笛卡儿积生成一张虚拟表VT1,表x有10万行数
据,表y有18万行数据,这意味着进行笛卡儿积后产生的虚拟表VT1
总共有180亿行的数据!因此运行这条SQL语句,会极其的慢:

mysql> SELECT COUNT(1) FROM x INNER JOIN y ON x.a=y.a;

语句执行速度慢的主要原因是需要产生180亿次的数据。
即便是在内存中产生这么多次的数据,也需要花费很长的时间。
然而,如果这时对表y添加一个主键值,再执行这条SQL语句,你会惊讶地发现
只需要0.06秒,具体情况如下:

mysql> SELECT COUNT(1) FROM x INNER JOIN y ON x.a=y.a;
+----------+
| COUNT(1) |
+----------+
|   100000 |
+----------+
1 row in set (0.06 sec)

在添加索引后避免了笛卡儿表的产生,因此大幅缩短了语句
运行的时间。我们可以通过EXPLAIN命令来查看经SQL优化器优化
后MySQL数据库实际选择的执行方式,如下所示:

mysql> EXPLAIN SELECT COUNT(1) FROM x INNER JOIN y ON x.a=y.a\G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: xtype: ALL
possible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 100425Extra: Using where
*************************** 2. row ***************************id: 1select_type: SIMPLEtable: ytype: eq_ref
possible_keys: PRIMARYkey: PRIMARYkey_len: 4ref: learn.x.arows: 1Extra: Using index
2 rows in set (0.00 sec)

要明白的是物理查
询会根据索引来进行优化,这也是MySQL数据库优化器的一项重要
工作。

《MySQL技术内幕(SQL编程)》——查询处理相关推荐

  1. mysql桦仔_Microsoft SQL Server 2005技术内幕:T-SQL查询笔记

    Microsoft SQL Server 2005技术内幕:T-SQL查询笔记 目录 f f f f f f f f 第二章 物理查询处理 分析,代数化,查询优化 f f f f f. 分析--> ...

  2. MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-02

    MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-02 6. 锁 ​ 人们认为行级锁总会增加开销.实际上,只有当实现本身会增加开销时,行级锁才会增加开销.InnoDB 存储引擎不需要锁升级,因 ...

  3. 读书笔记之MySQL技术内幕

    前言 本文内容基本摘抄自<MySQL技术内幕 InnoDB存储引擎>,以供复习之用,没有多少参考价值.想要更详细了解请参考原书. 第一章.MySQL体系结构和存储引擎 数据库是物理操作系统 ...

  4. mysql技术内幕sampdb_MySQL技术内幕汇总

    MySql技术内幕之MySQL入门(1) 检查系统中是否已经安装了MySQL sudo netstat -tap | grep mysql 若没有显示已安装结果,则没有安装.否则表示已经安装. sud ...

  5. mysql技术内幕sampdb_MySql技术内幕之MySQL入门(1)

    MySql技术内幕之MySQL入门(1) 安装 检查系统中是否已经安装了MySQL sudo netstat -tap | grep mysql 若没有显示已安装结果,则没有安装.否则表示已经安装. ...

  6. Mysql技术内幕InnoDB存储引擎——InnoDB存储引擎

    特此申明: 前段时间找工作所以看了<Mysql技术内幕InnoDB存储引擎>,整理的时候除了参考网上已有的笔记贴,加上自己整合的,可能和别人有雷同之处.不过无所谓啦,写出来自己看看,需要的 ...

  7. MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-01

    MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-01 1. MySQL体系结构和存储引擎 1.1 定义数据库和实例 数据库database: 物理操作系统文件或其他形式文件类型的集合. 当使 ...

  8. MySQL技术内幕 InnoDB存储引擎:锁问题(脏读、不可重复读)

    1.脏读 在理解脏读(Dirty Read)之前,需要理解脏数据的概念.但是脏数据和之前所介绍的脏页完全是两种不同的概念.脏页指的是在缓冲池中已经被修改的页,但是还没有刷新到磁盘中,即数据库实例内存中 ...

  9. MySQL必知必会教程:深入理解MySQL技术内幕

    2019独角兽企业重金招聘Python工程师标准>>> MySQL必知必会教程:深入理解MySQL技术内幕 作为最流行的开源数据库软件之一,MySQL数据库软件已经是广为人知了.当前 ...

  10. MySQL、Spark SQL 嵌套查询(二层、三层、多层)

    MySQL.Spark SQL 嵌套查询(二层.三层.多层) 二层查询 select * from(select * from(select substring(``,1,3) from `big1` ...

最新文章

  1. SolidEdge 工程图中如何标注尺寸公差
  2. 解决weblogic页面和控制台乱码问题
  3. Shell排序的原理与集体实现
  4. Linux网络子系统
  5. go context之WithTimeout的使用
  6. 深度学习 占用gpu内存 使用率为0_你了解GPU吗?为什么说深度学习需要GPU?
  7. Python--简单的端口扫描脚本
  8. java 画笔跟swing组件_Java学习教程(基础)--Java版本历史(二)
  9. ubuntu vim配置所有用户生效
  10. P2P穿透四种NAT类型
  11. #leetcode刷题之路39-组合总和
  12. OFD文件结构--OFD.xml
  13. win2012 加入域
  14. Difference between Vienna DL LLS and UL LLS
  15. 深度学习基础之图像分类
  16. C++编程练习:计算长方体体积、对象数组求学生成绩最高者、销售应用问题、重载复数加法运算
  17. ShardingSphere分库分表实战与核心原理
  18. CAPL学习之路-测试功能集函数(测试报告部分)
  19. Arcgis水文分析模块小流域划分流程
  20. 百度网盘登录测试用例

热门文章

  1. 女孩们,当你说没有好男人时请进来看看!
  2. 全角符号和半角符号的区别
  3. C#使用GET、POST请求获取结果
  4. python对拍程序
  5. MSVCRTD.lib(crtexe.obj) : error LNK2019: 无法解析的外部符号 _main,该符号在函数 ___tmainCRTStart...
  6. C# 使用JSON对数据序列化和反序列化.
  7. poj 1466 Girls and Boys
  8. python:configparser模块
  9. JQ怎样返回顶部代码
  10. 性能为王:选择模拟监控的10大理由!