《MySQL技术内幕(SQL编程)》——查询处理
查询可分为两种,逻辑查询处理表示执行查询应该产生什么样的结果,而物理查询代表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
在关系数据库中起逻辑表达式作用的除了TRUE
和FALSE
外,还有一种称为
三值逻辑的表达式。因为,在关系数据库中,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
过滤条件的返回值,
返回值有TRUE
、FALSE
、UNKNOWN
+-------------+-------------+----------+----------+-------------+
| 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 BY
的LIMIT
子句,结
果同样可能是无序的,因此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编程)》——查询处理相关推荐
- 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. 分析--> ...
- MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-02
MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-02 6. 锁 人们认为行级锁总会增加开销.实际上,只有当实现本身会增加开销时,行级锁才会增加开销.InnoDB 存储引擎不需要锁升级,因 ...
- 读书笔记之MySQL技术内幕
前言 本文内容基本摘抄自<MySQL技术内幕 InnoDB存储引擎>,以供复习之用,没有多少参考价值.想要更详细了解请参考原书. 第一章.MySQL体系结构和存储引擎 数据库是物理操作系统 ...
- mysql技术内幕sampdb_MySQL技术内幕汇总
MySql技术内幕之MySQL入门(1) 检查系统中是否已经安装了MySQL sudo netstat -tap | grep mysql 若没有显示已安装结果,则没有安装.否则表示已经安装. sud ...
- mysql技术内幕sampdb_MySql技术内幕之MySQL入门(1)
MySql技术内幕之MySQL入门(1) 安装 检查系统中是否已经安装了MySQL sudo netstat -tap | grep mysql 若没有显示已安装结果,则没有安装.否则表示已经安装. ...
- Mysql技术内幕InnoDB存储引擎——InnoDB存储引擎
特此申明: 前段时间找工作所以看了<Mysql技术内幕InnoDB存储引擎>,整理的时候除了参考网上已有的笔记贴,加上自己整合的,可能和别人有雷同之处.不过无所谓啦,写出来自己看看,需要的 ...
- MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-01
MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-01 1. MySQL体系结构和存储引擎 1.1 定义数据库和实例 数据库database: 物理操作系统文件或其他形式文件类型的集合. 当使 ...
- MySQL技术内幕 InnoDB存储引擎:锁问题(脏读、不可重复读)
1.脏读 在理解脏读(Dirty Read)之前,需要理解脏数据的概念.但是脏数据和之前所介绍的脏页完全是两种不同的概念.脏页指的是在缓冲池中已经被修改的页,但是还没有刷新到磁盘中,即数据库实例内存中 ...
- MySQL必知必会教程:深入理解MySQL技术内幕
2019独角兽企业重金招聘Python工程师标准>>> MySQL必知必会教程:深入理解MySQL技术内幕 作为最流行的开源数据库软件之一,MySQL数据库软件已经是广为人知了.当前 ...
- MySQL、Spark SQL 嵌套查询(二层、三层、多层)
MySQL.Spark SQL 嵌套查询(二层.三层.多层) 二层查询 select * from(select * from(select substring(``,1,3) from `big1` ...
最新文章
- SolidEdge 工程图中如何标注尺寸公差
- 解决weblogic页面和控制台乱码问题
- Shell排序的原理与集体实现
- Linux网络子系统
- go context之WithTimeout的使用
- 深度学习 占用gpu内存 使用率为0_你了解GPU吗?为什么说深度学习需要GPU?
- Python--简单的端口扫描脚本
- java 画笔跟swing组件_Java学习教程(基础)--Java版本历史(二)
- ubuntu vim配置所有用户生效
- P2P穿透四种NAT类型
- #leetcode刷题之路39-组合总和
- OFD文件结构--OFD.xml
- win2012 加入域
- Difference between Vienna DL LLS and UL LLS
- 深度学习基础之图像分类
- C++编程练习:计算长方体体积、对象数组求学生成绩最高者、销售应用问题、重载复数加法运算
- ShardingSphere分库分表实战与核心原理
- CAPL学习之路-测试功能集函数(测试报告部分)
- Arcgis水文分析模块小流域划分流程
- 百度网盘登录测试用例
热门文章
- 女孩们,当你说没有好男人时请进来看看!
- 全角符号和半角符号的区别
- C#使用GET、POST请求获取结果
- python对拍程序
- MSVCRTD.lib(crtexe.obj) : error LNK2019: 无法解析的外部符号 _main,该符号在函数 ___tmainCRTStart...
- C# 使用JSON对数据序列化和反序列化.
- poj 1466 Girls and Boys
- python:configparser模块
- JQ怎样返回顶部代码
- 性能为王:选择模拟监控的10大理由!