1.目标
通过本文可以了解在使用mysql数据库开发时,一些开发技巧。本文比较基础,大神请绕道。
通过本人能够掌握:
- MySQL 使用JOIN更新表
- MySQL 使用JOIN优化子查询
- MySQL 使用JOIN优化聚合子查询
- MySQL 实现分组选择
使用数据及导入方法见MYSQL-SQL开发总结(一)-SQL基础
2. 测试表数据
1 | mysql> SELECT * FROM apps; |
3. 使用JOIN更新表
3.1 测试场景
测试 apps 表中url字段与 websites表url相等的记录中,将 apps 的country字段都更改为‘中国’,预期目标效果如下:
3.2 用JOIN更新表失败
执行更新发现会报错,update的表不能出现在from语句中,原因是mysql对子查询的支持是比较薄弱的
1 | mysql> UPDATE apps SET country='中国' WHERE url IN (SELECT b.url FROM apps a JOIN websites b ON a.url = b.url); |
如下情况mysql 都会报错:
1 | In general, you cannot modify a table and select from the same table in a subquery. For example, this limitation applies to statements of the following forms: |
3.3 解决办法
官方手册推荐如下两种方式解决
内连接方式1
UPDATE apps a INNER JOIN websites b ON a.url = b.url SET a.country='中国';
嵌套一层1
UPDATE apps a JOIN (SELECT b.url FROM apps a JOIN websites b ON a.url = b.url) b ON a.url = b.url SET a.country='CN' ;
4.使用JOIN优化子查询
4.1 一般查询方法
1 | mysql> SELECT a.app_name,(SELECT NAME FROM websites b WHERE a.url = b.url ) AS app_name2 FROM apps a; |
问题:子查询对apps表的每一条记录都要进行一次子查询,
数据小时,没有多大影响,如果数据量大时,则要消耗大量的查寻
4.2 JOIN优化(左连接)后的写法
1 | mysql> SELECT a.app_name ,b.name FROM apps a LEFT JOIN websites b ON a.url = b.url ; |
5.使用JOIN优化聚合子查询
5.1 测试场景
统计website 表中不同应用类型在 access_log 表中登录count最大的记录中的日期。
5.2 一般写法,未能解决
无法达到预期效果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17mysql> SELECT w.name,MAX(a.count),a.date FROM websites AS w JOIN access_log a ON w.id = a.site_id GROUP BY w.name ,a.date ;
+----------+--------------+------------+
| name | MAX(a.count) | date |
+----------+--------------+------------+
| Facebook | 205 | 2016-05-14 |
| Facebook | 545 | 2016-05-16 |
| Google | 45 | 2016-05-10 |
| Google | 230 | 2016-05-14 |
| 微博 | 13 | 2016-05-15 |
| 淘宝 | 10 | 2016-05-14 |
| 菜鸟教程 | 100 | 2016-05-13 |
| 菜鸟教程 | 220 | 2016-05-15 |
| 菜鸟教程 | 201 | 2016-05-17 |
+----------+--------------+------------+
9 rows in set (0.00 sec)
mysql>
5.3 使用聚合子查询实现
1 | mysql> SELECT w.name,a.count,a.date FROM websites AS w JOIN access_log a ON w.id = a.site_id WHERE a.count = (SELECT MAX(c.count) FROM access_log c WHERE w.id = c.site_id); |
5.4 使用JOIN优化聚合子查询
优化查询效率1
2
3
4
5
6
7
8
9
10
11SELECT
w.name,
a.count,
a.date
FROM websites AS w
JOIN access_log a
ON w.id = a.site_id
JOIN access_log b
ON w.id = b.site_id
GROUP BY w.name,a.date,a.count
HAVING a.count = MAX(b.count);
1 | mysql> SELECT w.name,a.count,a.date FROM websites AS w JOIN access_log a ON w.id = a.site_id JOIN access_log b ON w.id = b.site_id GROUP BY w.name ,a.date,a.count HAVING a.count = MAX(b.count); |
6.实现分组选择
6.1 测试场景
查询website表中每种name的app在access_log 表中count字段数据最大的两条数据
6.2 传统模式
Google 公司网站访问次数最多的两条记录1
2
3
4
5
6
7
8
9
10mysql> SELECT w.name,a.date,a.count FROM websites AS w JOIN access_log a ON w.id = a.site_id WHERE w.name = 'Google' ORDER BY a.count DESC LIMIT 2 ;
+--------+------------+-------+
| name | date | count |
+--------+------------+-------+
| Google | 2016-05-14 | 230 |
| Google | 2016-05-10 | 45 |
+--------+------------+-------+
2 rows in set (0.00 sec)
mysql>
Facebook 公司网站访问次数最多的两条记录1
2
3
4
5
6
7
8
9
10mysql> SELECT w.name,a.date,a.count FROM websites AS w JOIN access_log a ON w.id = a.site_id WHERE w.name = 'Facebook' ORDER BY a.count DESC LIMIT 2 ;
+----------+------------+-------+
| name | date | count |
+----------+------------+-------+
| Facebook | 2016-05-16 | 545 |
| Facebook | 2016-05-14 | 205 |
+----------+------------+-------+
2 rows in set (0.00 sec)
mysql>
菜鸟教程公司网站访问次数最多的两条记录1
2
3
4
5
6
7
8
9
10mysql> SELECT w.name,a.date,a.count FROM websites AS w JOIN access_log a ON w.id = a.site_id WHERE w.name = '菜鸟教程' ORDER BY a.count DESC LIMIT 2 ;
+----------+------------+-------+
| name | date | count |
+----------+------------+-------+
| 菜鸟教程 | 2016-05-15 | 220 |
| 菜鸟教程 | 2016-05-17 | 201 |
+----------+------------+-------+
2 rows in set (0.01 sec)
mysql>
缺点:
- 1 如果分类或是应用类型很多的情况下则需要多次执行同一查询
- 2 增加应用程序同数据的交互次数
- 3 增加数据库执行查询的次数,不符合批处理原则
- 4 增加网络流量
6.2 通过join和子查询实现分组
1 | SELECT |
结果:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15+----------+------------+-------+
| name | date | count |
+----------+------------+-------+
| Google | 2016-05-14 | 230 |
| Google | 2016-05-10 | 45 |
| 淘宝 | 2016-05-14 | 10 |
| 菜鸟教程 | 2016-05-15 | 220 |
| 菜鸟教程 | 2016-05-17 | 201 |
| 微博 | 2016-05-15 | 13 |
| Facebook | 2016-05-16 | 545 |
| Facebook | 2016-05-14 | 205 |
+----------+------------+-------+
8 rows in set (0.00 sec)
mysql>