Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2312298
  • 博文数量: 473
  • 博客积分: 12252
  • 博客等级: 上将
  • 技术积分: 4307
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-12 10:02
文章分类

全部博文(473)

文章存档

2012年(8)

2011年(63)

2010年(73)

2009年(231)

2008年(98)

分类: Mysql/postgreSQL

2012-01-12 12:31:13

  1. CREATE DATABASE mysql_join_demo;

  2. CREATE TABLE users(
  3.  id INT NOT NULL AUTO_INCREMENT,
  4.  name VARCHAR(100) NOT NULL DEFAULT '',
  5.  pass VARCHAR(100) NOT NULL DEFAULT '',
  6.  age INT NOT NULL DEFAULT 0,
  7.  address VARCHAR(100) NOT NULL DEFAULT '',
  8.  PRIMARY KEY(id)
  9. );

  10. CREATE TABLE orders(
  11.  id INT NOT NULL AUTO_INCREMENT,
  12.  name VARCHAR(100) NOT NULL DEFAULT '',
  13.  user_id INT NOT NULL DEFAULT 0,
  14.  price FLOAT NOT NULL DEFAULT 0,
  15.  PRIMARY KEY(id)
  16. );

  17. INSERT INTO users(name,pass,age,address)
  18. VALUES
  19. ('neo','123',23,'Beijing'),
  20. ('neo','123',23,'Beijing'),
  21. ('neo','123',23,'Beijing'),
  22. ('neo','123',23,'Beijing');

  23. INSERT INTO orders(name,user_id,price)
  24. VALUES('order-1',1,12.3),('order-2',1,12.4),('order-3',1,12.4),('order-4',2,12.5);

1.交叉查询
交叉查询就是将多个表做笛卡尔积,也就是一个交叉乘积

 

  1. mysql> SELECT * FROM users,orders;
  2. +----+------+------+-----+---------+----+---------+---------+-------+

  3. | id | name | pass | age | address | id | name | user_id | price |
  4. +----+------+------+-----+---------+----+---------+---------+-------+

  5. | 1 | neo | 123 | 22 | Beijing | 1 | order-1 | 1 | 12.3 |
  6. | 1 | neo | 123 | 22 | Beijing | 2 | order-2 | 1 | 12.4 |
  7. | 1 | neo | 123 | 22 | Beijing | 3 | order-3 | 1 | 12.4 |
  8. | 1 | neo | 123 | 22 | Beijing | 4 | order-4 | 2 | 12.5 |
  9. | 2 | neo | 123 | 23 | Beijing | 1 | order-1 | 1 | 12.3 |
  10. | 2 | neo | 123 | 23 | Beijing | 2 | order-2 | 1 | 12.4 |
  11. | 2 | neo | 123 | 23 | Beijing | 3 | order-3 | 1 | 12.4 |
  12. | 2 | neo | 123 | 23 | Beijing | 4 | order-4 | 2 | 12.5 |
  13. | 3 | neo | 123 | 23 | Beijing | 1 | order-1 | 1 | 12.3 |
  14. | 3 | neo | 123 | 23 | Beijing | 2 | order-2 | 1 | 12.4 |
  15. | 3 | neo | 123 | 23 | Beijing | 3 | order-3 | 1 | 12.4 |
  16. | 3 | neo | 123 | 23 | Beijing | 4 | order-4 | 2 | 12.5 |
  17. | 4 | neo | 123 | 23 | Beijing | 1 | order-1 | 1 | 12.3 |
  18. | 4 | neo | 123 | 23 | Beijing | 2 | order-2 | 1 | 12.4 |
  19. | 4 | neo | 123 | 23 | Beijing | 3 | order-3 | 1 | 12.4 |
  20. | 4 | neo | 123 | 23 | Beijing | 4 | order-4 | 2 | 12.5 |
  21. | 5 | neo | 123 | 23 | Beijing | 1 | order-1 | 1 | 12.3 |
  22. | 5 | neo | 123 | 23 | Beijing | 2 | order-2 | 1 | 12.4 |
  23. | 5 | neo | 123 | 23 | Beijing | 3 | order-3 | 1 | 12.4 |
  24. | 5 | neo | 123 | 23 | Beijing | 4 | order-4 | 2 | 12.5 |
  25. +

交叉查询+两个表的对等条件=inner join

 

  1. mysql> SELECT * FROM users u,orders o WHERE u.id=o.user_id;
  2. +----+------+------+-----+---------+----+---------+---------+-------+

  3. | id | name | pass | age | address | id | name | user_id | price |
  4. +----+------+------+-----+---------+----+---------+---------+-------+

  5. | 1 | neo | 123 | 22 | Beijing | 1 | order-1 | 1 | 12.3 |
  6. | 1 | neo | 123 | 22 | Beijing | 2 | order-2 | 1 | 12.4 |
  7. | 1 | neo | 123 | 22 | Beijing | 3 | order-3 | 1 | 12.4 |
  8. | 2 | neo | 123 | 23 | Beijing | 4 | order-4 | 2 | 12.5 |
  9. +----+------+------+-----+---------+----+---------+---------+-------+


  10. mysql> SELECT * FROM users u INNER JOIN orders o ON u.id=o.user_id;
  11. +----+------+------+-----+---------+----+---------+---------+-------+

  12. | id | name | pass | age | address | id | name | user_id | price |
  13. +----+------+------+-----+---------+----+---------+---------+-------+

  14. | 1 | neo | 123 | 22 | Beijing | 1 | order-1 | 1 | 12.3 |
  15. | 1 | neo | 123 | 22 | Beijing | 2 | order-2 | 1 | 12.4 |
  16. | 1 | neo | 123 | 22 | Beijing | 3 | order-3 | 1 | 12.4 |
  17. | 2 | neo | 123 | 23 | Beijing | 4 | order-4 | 2 | 12.5 |
  18. +

left join
left join主要以from后面的表为基础表,对于join的表没有与其对应的补NULL

 

  1. mysql> SELECT * FROM users u LEFT JOIN orders o ON u.id=o.user_id;
  2. +----+------+------+-----+---------+------+---------+---------+-------+

  3. | id | name | pass | age | address | id | name | user_id | price |
  4. +----+------+------+-----+---------+------+---------+---------+-------+

  5. | 1 | neo | 123 | 22 | Beijing | 1 | order-1 | 1 | 12.3 |
  6. | 1 | neo | 123 | 22 | Beijing | 2 | order-2 | 1 | 12.4 |
  7. | 1 | neo | 123 | 22 | Beijing | 3 | order-3 | 1 | 12.4 |
  8. | 2 | neo | 123 | 23 | Beijing | 4 | order-4 | 2 | 12.5 |
  9. | 3 | neo | 123 | 23 | Beijing | NULL | NULL | NULL | NULL |
  10. | 4 | neo | 123 | 23 | Beijing | NULL | NULL | NULL | NULL |
  11. | 5 | neo | 123 | 23 | Beijing | NULL | NULL | NULL | NULL |
  12. +

right join不会补齐,而是将不存在的NULL值去掉

 

  1. mysql> SELECT * FROM users u RIGHT JOIN orders o ON u.id=o.user_id;
  2. +------+------+------+------+---------+----+---------+---------+-------+

  3. | id | name | pass | age | address | id | name | user_id | price |
  4. +------+------+------+------+---------+----+---------+---------+-------+

  5. | 1 | neo | 123 | 22 | Beijing | 1 | order-1 | 1 | 12.3 |
  6. | 1 | neo | 123 | 22 | Beijing | 2 | order-2 | 1 | 12.4 |
  7. | 1 | neo | 123 | 22 | Beijing | 3 | order-3 | 1 | 12.4 |
  8. | 2 | neo | 123 | 23 | Beijing | 4 | order-4 | 2 | 12.5 |
  9. +

mysql的join在添加条件的时候可以使用using关键字,前提是两个关联字段必须一样-_-!

mysql的join原理

mysql join采用的算法就是Nested-Loop Join 传送门(http://dev.mysql.com/doc/refman/5.0/en/nested-loop-joins.html),

例如一个SQL是这样的select * from users join orders,这个东西在mysql内部的实现的伪代码

  1. FOR ORDER IN orders{
  2.  FOR USER IN users{
  3.     send USER+ORDER
  4.  }
  5. }

这里还需要描述一个join_buffer_size,这个值定义当执行join操作的时候系统分配的内存

上面的查询其实已经使用了join_buffer,看执行计划里面Extra这个值Using join buffer

 

  1. mysql> EXPLAIN SELECT SQL_NO_CACHE * FROM users JOIN orders;
  2. +----+-------------+--------+------+---------------+------+---------+------+------+-------------------+

  3. | id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | REF | ROWS | Extra |
  4. +----+-------------+--------+------+---------------+------+---------+------+------+-------------------+

  5. | 1 | SIMPLE | orders | ALL | NULL | NULL | NULL | NULL | 4 | |
  6. | 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 5 | USING JOIN buffer |
  7. +

(这里预留一个问题,为什么以orders表做了基表?)

join buffer使用就是将外层的查询结果放置在一片内存里,这块内存就是join buffer,大小就是系统启动时候设置的join_buffer_size

1.join buffer在join的查询为ALL,index,range的时候
2.一个语句可能用到多个join buffer
3.join buffer在语句执行完的时候被释放

 

  1. mysql> EXPLAIN SELECT SQL_NO_CACHE * FROM users JOIN orders JOIN users u;
  2. +----+-------------+--------+------+---------------+------+---------+------+------+-------------------+

  3. | id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | REF | ROWS | Extra |
  4. +----+-------------+--------+------+---------------+------+---------+------+------+-------------------+

  5. | 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 5 | |
  6. | 1 | SIMPLE | orders | ALL | NULL | NULL | NULL | NULL | 5 | USING JOIN buffer |
  7. | 1 | SIMPLE | u | ALL | NULL | NULL | NULL | NULL | 5 | USING JOIN buffer |
  8. +

为什么用orders做基表,因为orders表里面只有4条记录,而users表里面有5条记录,mysql的优化器在优化的时候,会以扫描记录数量的多少来决定以哪个表作为基表

  1. mysql> INSERT INTO orders(name,user_id) VALUES('order-5',2);
  2. mysql> EXPLAIN SELECT SQL_NO_CACHE * FROM users JOIN orders;
  3. +----+-------------+--------+------+---------------+------+---------+------+------+-------------------+

  4. | id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | REF | ROWS | Extra |
  5. +----+-------------+--------+------+---------------+------+---------+------+------+-------------------+

  6. | 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 5 | |
  7. | 1 | SIMPLE | orders | ALL | NULL | NULL | NULL | NULL | 5 | USING JOIN buffer |
  8. +

参考:
http://dev.mysql.com/doc/refman/5.0/en/nested-loop-joins.html

http://www.mysqlperformanceblog.com/2010/07/05/how-is-join_buffer_size-allocated/

阅读(1598) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~