[关闭]
@shanyy 2017-08-02T01:34:39.000000Z 字数 7192 阅读 1373

MYSQL常用技巧

mysql 智课网


维护mysql 和postgres 的时候会踩到很多坑,这里总结一些,一面后面再遇到。
如果不习惯简书的markdown排版可以点这里,后续的更新可能不一定会及时同步到简书。个人笔记版

初始化

  1. CREATE DATABASE mydbname CHARACTER SET utf8;
  2. ALTER DATABASE SET CHARACTER utf8;

执行sql文件

sql脚本可以通过下面两种方式执行:

  1. -- 直接连接执行
  2. mysql --host shanyy.me --user user --database test < test-func.sql
  3. -- source 执行
  4. mysql > source some.sql

mycli执行sql的时候好像老是会报错,不知道为啥,可能是我配置的不对吧,如果遇到同样的情况换mysql自带的就好了。

mysql的函数(function)和过程(procedure)

在维护mysql和procedure中总会遇到需要有些无法通过简单的sql完成的需求,一般会想到sql脚本完成。这时候就会遇到sql函数和过程。函数和过程很像,在官方文档里也是放在一起讲的。mysql官方文档——函数和过程
函数
先说函数,函数相对比较简单,而且限制也多一些。下面是一个官方文档抄过来的例子:

  1. -- 定义函数名和输入参数
  2. mysql> CREATE FUNCTION hello (s CHAR(20))
  3. -- 定义返回参数类型
  4. mysql> RETURNS CHAR(50)
  5. -- 函数代码段
  6. -> RETURN CONCAT('Hello, ',s,'!');
  7. Query OK, 0 rows affected (0.00 sec)
  8. -- 可以直接在sql语句中执行函数
  9. mysql> SELECT hello('world');
  10. +----------------+
  11. | hello('world') |
  12. +----------------+
  13. | Hello, world! |
  14. +----------------+
  15. 1 row in set (0.00 sec)

函数的执行过程和内置函数一模一样,你就把它理解为内置函数就可以了,可以直接在sql中用。

定义一个函数很简单,复杂的函数也就是函数体可能复杂点,下面是一个稍微复杂点的,实际上这个函数屁用没有,就是为了展示几个常见问题:

  1. drop function if exists test;
  2. DELIMITER $$
  3. create function test()
  4. returns varchar(100) NONDETERMINISTIC
  5. begin
  6. declare size int;
  7. declare k int;
  8. declare s datetime;
  9. declare m float;
  10. declare x double;
  11. declare c1 int;
  12. set size = 1000;
  13. set k = 0;
  14. while k < size do
  15. select cast(count(*) as char) into c1 from draft;
  16. set k = k + 1;
  17. end while;
  18. repeat
  19. select cast(count(*) as char) into c1 from draft;
  20. set k = k - 1;
  21. until k > 0
  22. end repeat;
  23. if c1 > 1000 then
  24. set c1 = 999;
  25. else
  26. set c1 = 1001;
  27. end if;
  28. return c1;
  29. end $$
  30. DELIMITER ;

为了大家好复制,就不在代码片里直接注释了,下面来逐行分析。

  1. drop function if exists test;
  1. DELIMITER $$
  1. returns varchar(100) NONDETERMINISTIC
  1. begin
  2. ...
  3. end

有了这些基础,我们开始尝试着做一些完成一个很常见的需求:如何用mysql快速填充一个测试表。虽然利用python或者nodejs填充表格也很简单,但是效率最高的还是直接使用sql来做。
于是乎,我们尝试写出了下面的代码:

  1. -- 实际上这个代码是无法执行的!!!
  2. drop function if exists initProj;
  3. DELIMITER $$
  4. create function initProj()
  5. begin
  6. declare size int;
  7. declare k int;
  8. drop table tmp_table;
  9. create table tmp_table ( id int(11) not null auto_increment primary key,
  10. time datetime,
  11. rand_data int(10),
  12. rand_str varchar(100));
  13. set size = 1000;
  14. set k = 0;
  15. while size > k do
  16. insert into tmp_table (time, rand_data, rand_str) values (now(), 1000000 * rand(), rand_string(100));
  17. set k = k + 1;
  18. end while ;
  19. end $$
  20. DELIMITER ;

这里之所以错误是因为mysql不允许隐式或显示提交,简单理解就是drop table, create table, truncate table之类的操作都没法执行。有时候你需要清理表格可以考虑利用delete from some_table where id > 0;来做,不过不建议这么做,下面介绍的procedure来做更加优雅。


过程
过程和函数很类似,只不过过程的限制没有函数那么多,带来的副作用就是调用过程需要主动地call procedure而不是直接在sql中调用。

  1. -- 调用procedure的例子
  2. -- \G 参数主要是输出的排版更加友好
  3. call exp_procedure() \G;

过程的定义,函数体都和函数是一样的,这里就不具体介绍了,可以简单理解procedure为一坨代码放到一起实现一个功能。下面是利用procedure和function一起实现的初始化表格的需求。

  1. -- 生成随机字符串
  2. DELIMITER $$
  3. drop function if exists rand_string;
  4. CREATE FUNCTION `rand_string`(n INT)
  5. RETURNS varchar(255)
  6. BEGIN
  7. DECLARE chars_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  8. DECLARE return_str varchar(255) DEFAULT '';
  9. DECLARE i INT DEFAULT 0;
  10. WHILE i < n DO
  11. SET return_str = concat(return_str,substring(chars_str , FLOOR(1 + RAND()*62 ),1));
  12. SET i = i +1;
  13. END WHILE;
  14. RETURN return_str;
  15. END $$
  16. DELIMITER ;
  17. select rand_string(100);
  18. -- 初始化表格
  19. drop procedure if exists initProj;
  20. DELIMITER $$
  21. create procedure initProj(size int)
  22. begin
  23. declare k int;
  24. drop table tmp_table;
  25. create table tmp_table ( id int(11) not null auto_increment primary key,
  26. time datetime,
  27. rand_data int(10),
  28. rand_str varchar(100));
  29. set k = 0;
  30. while size > k do
  31. insert into tmp_table (time, rand_data, rand_str) values (now(), 1000000 * rand(), rand_string(100));
  32. set k = k + 1;
  33. end while ;
  34. end $$
  35. DELIMITER ;

只需要call initProj(100000);即可完成初始化。

其中随机字符串为了图简单没有自己写,网上一搜一大堆,我找了一个拿过来用了,丢掉了一些我不太关心的内容。比如权限之类的,有兴趣可以自己去看,这里吧连接放出来了。随机字符串博客链接

最后初始化十万个数据花费了5分钟的时间, 如果不做随机,速度会更快。

更快地生成测试数据

偶然看到了阿里的慢sql优化的新闻,看了生成测试数据的sql,发现insert by select速度要远远快于一个一个地插入,还没研究为啥,先做个笔记,这里先把sql贴出来,仅供参考。

  1. create table a (id int auto_increment,seller_id bigint,seller_name varchar(100) collate utf8_bin ,gmt_create varchar(30),primary key(id));
  2. insert into a (seller_id,seller_name,gmt_create) values (100000,'uniqla','2017-01-01');
  3. insert into a (seller_id,seller_name,gmt_create) values (100001,'uniqlb','2017-02-01');
  4. insert into a (seller_id,seller_name,gmt_create) values (100002,'uniqlc','2017-03-01');
  5. insert into a (seller_id,seller_name,gmt_create) values (100003,'uniqld','2017-04-01');
  6. insert into a (seller_id,seller_name,gmt_create) values (100004,'uniqle','2017-05-01');
  7. insert into a (seller_id,seller_name,gmt_create) values (100005,'uniqlf','2017-06-01');
  8. insert into a (seller_id,seller_name,gmt_create) values (100006,'uniqlg','2017-07-01');
  9. insert into a (seller_id,seller_name,gmt_create) values (100007,'uniqlh','2017-08-01');
  10. insert into a (seller_id,seller_name,gmt_create) values (100008,'uniqli','2017-09-01');
  11. insert into a (seller_id,seller_name,gmt_create) values (100009,'uniqlj','2017-10-01');
  12. insert into a (seller_id,seller_name,gmt_create) values (100010,'uniqlk','2017-11-01');
  13. insert into a (seller_id,seller_name,gmt_create) values (100011,'uniqll','2017-12-01');
  14. insert into a (seller_id,seller_name,gmt_create) values (100012,'uniqlm','2018-01-01');
  15. insert into a (seller_id,seller_name,gmt_create) values (100013,'uniqln','2018-02-01');
  16. insert into a (seller_id,seller_name,gmt_create) values (100014,'uniqlo','2018-03-01');
  17. insert into a (seller_id,seller_name,gmt_create) values (100015,'uniqlp','2018-04-01');
  18. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  19. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  20. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  21. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  22. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  23. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  24. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  25. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  26. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  27. insert into a (seller_id,seller_name,gmt_create) select seller_id,seller_name,gmt_create from a;
  28. insert into a (seller_id,seller_name,gmt_create) values (100016,'uniqlq',now());
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注