# 014.科普.有生产力的Sql语句
不等不靠,有囧有料。终日乾乾,或跃在渊。
如果,我们做足了一些细节,敲出不够烂的代码,
那么,不少企业就会倒闭,信息化建设就会倒退。
如果,我们做不足一些细节,依赖于流水线。
那么,高效生产的同时,我们会退化为码工。
@史荣久 / 2015-03-27 / CC-BY-SA-3.0
## 观看视频
* [优酷视频(被转720P)](http://v.youku.com/v_show/id_XOTIwODUyNDA4.html)
* [腾讯视频(被转720P)](http://v.qq.com/page/g/u/k/g0150g2ftuk.html)
* [百度网盘(原始1080P)](http://pan.baidu.com/share/link?shareid=3935315343&uk=1380913564&fid=395714801385233)
## 内容摘要
* 安迪-比尔定律(Andy and Bill’s Law)
* 依赖于框架流水线,我们会从手艺人退化为流水线上的码工
* 解释和部分解决Mysql的order-by-limit巨慢
* 分页问题,引申出的sublist,substring
* 一条语句,显示学生所选的课程:GROUP_CONCAT
* 各GROUP的TOP-N问题(分组内,各取前N个)
* 自增主键是个坑,尽量避免(尤其分布式)
* 大量插入(bulk insert),VALUES
* 插入忽略:INSERT IGNORE
* 插入更新:ON DUPLICATE KEY UPDATE(有bug变的特性)
* 替换插入:REPLACE INTO
* 大量删除:DELETE & TRUNCATE(索引,事务,自增)
* 多表联合删除,子查询删除,快速删除
* 关联更新:单个字段,多个字段
* 执行计划:explain,其他优化
* 建立索引:根据sql和explain建立必要的索引
* JDBC: PreparedStatement(DML) vs Statement(DDL)
* JDBC: addBatch, executeBatch 的性能
* JDBC: allowMultiQueries,maxAllowedPacket 安全和速度
## 参考资源
* [安迪-比尔定律](http://www.baike.com/wiki/安迪-比尔定律)
* [解释:mysql-order-by-limit](http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/)
* [解释:late-row-lookups](http://explainextended.com/2011/02/11/late-row-lookups-innodb)
* [subList OOM,注意jdk版本](http://skydream.iteye.com/blog/1672745)
* [Mysql-5.5 性能优化](http://dev.mysql.com/doc/refman/5.5/en/statement-optimization.html)
* [Mysql-5.5 DML:增(insert)](http://dev.mysql.com/doc/refman/5.5/en/insert.html)
* [Mysql-5.5 DML:删(delete)](http://dev.mysql.com/doc/refman/5.5/en/delete.html)
* [Mysql-5.5 DML:改(update)](http://dev.mysql.com/doc/refman/5.5/en/update.html)
* [Mysql-5.5 DML:查(select)](http://dev.mysql.com/doc/refman/5.5/en/select.html)
* [Mysql-5.5 子查询(subqueries)](http://dev.mysql.com/doc/refman/5.5/en/subqueries.html)
* [Mysql-5.5 插入或替换(replace)](http://dev.mysql.com/doc/refman/5.5/en/replace.html)
* [Mysql-5.5 重复时更新(duplicate)](http://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html)
* [Mysql-5.5 聚集:列变行](http://dev.mysql.com/doc/refman/5.5/en/group-by-functions.html)
* [Mysql-5.5 聚集:合计](http://dev.mysql.com/doc/refman/5.5/en/group-by-modifiers.html)
* [Statement vs PreparedStatement](http://stackoverflow.com/questions/3271249)
* [Values vs JDBC批量预处理](http://brian.pontarelli.com/2011/06/21/jdbc-batch-vs-multi-row-inserts)
* [JDBC-URL 能用到的参数](http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html)
## 欢迎围观
if (you.accept(MoilionCircle.SPIRIT)) { if(you.haveADL()){ MoilionCircle we = you.search(MoilionCircle.SLOGAN); we.welcome(you); } if(you.share(this)){ We.thank(you); We.mayFind7Moilion(); } }
## 测试SQL
select version(); -- 5.5.41-0ubuntu0.14.04.1 -- 建库 DROP DATABASE IF EXISTS `moilioincircle_r014`; CREATE DATABASE `moilioincircle_r014` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; USE moilioincircle_r014; -- 建表 DROP TABLE IF EXISTS `STUDENT`; CREATE TABLE `STUDENT` ( `ID` int(11) NOT NULL, `NAME` varchar(45) NOT NULL, `GENDER` int(11) NOT NULL DEFAULT '1', PRIMARY KEY (`ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `COURSE`; CREATE TABLE `COURSE` ( `ID` int(11) NOT NULL, `NAME` varchar(45) COLLATE utf8_bin NOT NULL, PRIMARY KEY (`ID`), UNIQUE KEY `NAME_UNIQUE` (`NAME`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `STUDENT_COURSE_MAP`; CREATE TABLE `STUDENT_COURSE_MAP` ( `STUDENT_ID` int(11) NOT NULL, `COURSE_ID` int(11) NOT NULL, PRIMARY KEY (`STUDENT_ID`,`COURSE_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `EXAM`; CREATE TABLE `EXAM` ( `STUDENT_ID` int(11) NOT NULL, `COURSE_ID` int(11) NOT NULL, `SCORE` int(11) NOT NULL, PRIMARY KEY (`STUDENT_ID`,`COURSE_ID`), KEY `IDX_SCORE` (`SCORE`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; DROP TABLE IF EXISTS `AUTOINCR`; CREATE TABLE `AUTOINCR` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `NAME` varchar(45), PRIMARY KEY (`ID`) ) AUTO_INCREMENT = 100 ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -- 数据 INSERT INTO STUDENT (ID,NAME,GENDER) VALUES (1,'学生1',2), (2,'学生2',1), (3,'学生3',NULL), (4,'学生4',DEFAULT); INSERT INTO COURSE (ID,NAME) VALUES (1,'课程1'), (2,'课程2'), (3,'课程3'), (4,'课程4'); INSERT INTO STUDENT_COURSE_MAP (STUDENT_ID,COURSE_ID) VALUES (1,1), (2,1),(2,2), (3,1),(3,2),(3,3), (4,1),(4,2),(4,3),(4,4); INSERT INTO EXAM (STUDENT_ID,COURSE_ID,SCORE) VALUES (1,1,90),(1,2,70),(1,3,85),(1,4,80), (2,1,70),(2,2,85),(2,3,75),(2,4,80), (3,1,75),(3,2,85),(3,3,85),(3,4,65), (4,1,60),(4,2,75),(4,3,80),(4,4,85); INSERT INTO AUTOINCR (ID,NAME) VALUES (1,'自增1'), (DEFAULT,'自增#1'), (5,'自增5'), (DEFAULT,'自增#2'); -- 查 ----------------- -- 学生都选了什么课(把列换成行显示) -- set group_concat_max_len=10000; SELECT S.NAME, GROUP_CONCAT(C.NAME ORDER BY C.NAME ) AS COURSES FROM STUDENT AS S, COURSE AS C, STUDENT_COURSE_MAP AS M WHERE S.ID = M.STUDENT_ID AND C.ID = M.COURSE_ID GROUP BY S.NAME HAVING COUNT(C.NAME)>1; -- 把各科考试,前三名取出来。 -- MYSQL 没有 ROW_NUMBER() OVER(PARTITION BY A ORDER BY B DESC) SELECT C.NAME AS COURSE, S.NAME AS STUDENT, E.SCORE FROM EXAM AS E , STUDENT AS S, COURSE AS C WHERE (SELECT COUNT(*) FROM EXAM AS B WHERE B.COURSE_ID = E.COURSE_ID AND B.SCORE >= E.SCORE ) <= 3 AND E.STUDENT_ID = S.ID AND E.COURSE_ID = C.ID ORDER BY COURSE ASC, SCORE DESC; SELECT * FROM STUDENT WHERE (ID,NAME) IN ((1,'学生1'),(2,'学生2')); -- ------- 增 ---------- SELECT * FROM COURSE; INSERT IGNORE INTO COURSE (ID,NAME) VALUES (1,'课程1'), (11,'课程1'), (5,'课程5'), (6,'课程6'); REPLACE INTO COURSE (ID,NAME) VALUES (5,'课程55'), (66,'课程6'), (7,'课程7'); INSERT INTO COURSE (ID,NAME) VALUES (5,'课程5'),(6,'课程6'),(8,'课程6') ON DUPLICATE KEY UPDATE NAME=VALUES(NAME),ID=VALUES(ID); INSERT INTO COURSE (ID,NAME) VALUES (5,'课程5'),(6,'课程6'),(7,'课程7') ON DUPLICATE KEY UPDATE NAME=VALUES(NAME), ID=(CASE WHEN NAME = VALUES(NAME) THEN VALUES(ID) ELSE ID END); -- 删 CREATE TABLE AUTOINCR_1 LIKE AUTOINCR; -- 表结构相同 INSERT INTO AUTOINCR_1 SELECT * FROM AUTOINCR; DESCRIBE AUTOINCR_1; CREATE TABLE AUTOINCR_2 SELECT * FROM AUTOINCR WHERE ID <10; -- 不相同 DESCRIBE AUTOINCR_2; SELECT * FROM AUTOINCR_1; SELECT * FROM AUTOINCR_2; DELETE FROM AUTOINCR_1; INSERT INTO AUTOINCR_1 (NAME) VALUES ('课程1'); TRUNCATE TABLE AUTOINCR_1; DELETE T1,T2 FROM AUTOINCR_1 AS T1,AUTOINCR_2 AS T2 WHERE T1.ID = T2.ID; DELETE QUICK FROM AUTOINCR_2; OPTIMIZE TABLE AUTOINCR_2; -- 改 ------ INSERT INTO AUTOINCR_1 SELECT ID,NULL FROM AUTOINCR; INSERT INTO AUTOINCR_2 SELECT * FROM AUTOINCR WHERE ID <10; -- 更新单个字段 UPDATE AUTOINCR_2 AS T2, AUTOINCR_1 AS T1 SET T1.NAME = T2.NAME WHERE T2.ID = T1.ID; UPDATE AUTOINCR_1 SET NAME=NULL; UPDATE AUTOINCR_1 AS T1 SET T1.NAME = (SELECT T2.NAME FROM AUTOINCR_2 AS T2 WHERE T2.ID = T1.ID); CREATE TABLE STUDENT_1 LIKE STUDENT; INSERT INTO STUDENT_1 SELECT ID,CONCAT(NAME,'#'),0 FROM STUDENT; SELECT * FROM STUDENT; SELECT * FROM STUDENT_1; -- 更新多个字段 UPDATE STUDENT_1 AS T1 INNER JOIN (SELECT T.ID, T.NAME, T.GENDER FROM STUDENT AS T) AS T2 ON T2.ID = T1.ID SET T1.NAME = T2.NAME ,T1.GENDER = T2.GENDER;
题图:Intel Corp. President Andy Grove, right, shakes hands with Microsoft Chairman Bill Gates at a meeting in Burlingame, Ca., on Monday Nov. 9, 1992, as they team up to offer a new product of videos on personal computers.。
原文: http://www.moilioncircle.com/release/014.know.productive-crud-mysql.html