最近笔者在做MySQL脚本的移植和测试。在这个过程中,我发现了MySQL数据库中一些需要优化的地方。我写这篇文章是为了给相关项目的开发者一个参考。1、存储过程中参数名使用错误的问题。例如在MySQL数据库中创建如下表tb_testnum:droptableifexiststb_testnum;createtabletb_testnum(boxnumbervarchar(30)notnull,usertypeintnotnull);createuniqueindexidx1_tb_testnumontb_testnum(boxnumber);同时创建如下存储过程pr_dealtestnum:;注意,“selectcount(*)intop_boxnumcountfromTheparameter"p_boxnumber"inthetb_testnumwhereboxnumber=p_boxnumber;”语句与输入参数“p_boxnumber”不同(少了一个r),并且这个参数没有定义在存储过程。将存储过程pr_dealtestnum放到pr_dealtestnum.sql文件中,使用命令行运行脚本文件,发现MySQL数据库不报错:>mysql-uroot-p'root'-h10.10.10.10-P3306-Ddbtestcallpr_dealtestnum('2344273522');ERROR1054(42S22):Unknowncolumn'p_boxnumbe'in'whereclause'这样,问题就来了,是不是MySQL数据库没有严格检查存储过程中使用的参数名?第二,存储过程中使用的参数名前面有多余的符号。这道题和第一道题类似,只是“参数名错误”变成了“参数名前面有多余的符号”。比如我们仍然使用问题1中的表tb_testnum,往表中插入数据:insertintotb_testnum(boxnumber,usertype)values('2344273522',1);11同时创建如下存储过程pr_dealtestnum:dropprocedureifexistspr_dealtestnum;delimiter//createprocedurepr_dealtestnum(inp_boxnumbervarchar(30))pr_dealtestnum_label:begindeclarep_boxnumcountint;selectcount(*)intop_boxnumcountfromtb_testnumwhereboxnumber=@p_boxnumber;selectp_boxnumcount;leavepr_dealtestnum_label;end;//delimiter;select'createprocedurepr_dealtestnumok';注意)into“selectcount,”selectcount(*)whereboxnumber=@p_boxnumber;”语句中的参数“@p_boxnumber”是输入参数“p_boxnumber”前加的@符号。将存储过程pr_dealtestnum放到pr_dealtestnum.sql文件中,使用命令行运行脚本文件,发现MySQL数据库不报错:>mysql-uroot-p'root'-h10.10.10.10-P3306-Ddbtestcallpr_dealtestnum('2344273522');+----------------+|p_boxnumcount|+----------------+|0|+--------------+1rowinset(0.00sec)QueryOK,0rowsaffected(0.00sec)because前面我们在表tb_testnum中插入了一条数据,所以正确的输出应该是1,而不是0。我们去掉语句“selectcount(*)intop_boxnumcountfromtb_testnumwhereboxnumber=”中“@p_boxnumber”中的@符号@p_boxnumber;"并放入MySQL数据库运行。我们发现“调用pr_dealtestnum('2344273522');”之后,输出结果是正确的。这也说明MySQL数据库没有严格检查存储过程中使用的参数名。3、存储过程中向表中插入冗余数据的问题。比如前面两题我们还是用tb_testnum这个表。如果直接向表中插入冗余数据,MySQL数据库会报错:mysql>insertintotb_testnum(boxnumber,usertype)values('2344273523',1,1);ERROR1136(21S01):Columncountdoes'tmatchvaluecountatrow1,报错原因是表tb_testnum只有两列,但要向其中插入三列数据。接着,创建如下存储过程pr_dealtestnum:dropprocedureifexistspr_dealtestnum;delimiter//createprocedurepr_dealtestnum(inp_boxnumbervarchar(30),inp_usertypeint)pr_dealtestnum_label:begininsertintotb_testnum(boxnumber,usertype)values(p_boxnumber,p_usertype,1);leavepr_dealtestnum_label;end;//delimiter;select'createprocedurepr_dealtestnumok';请注意“insertintotb_testnum(boxnumber,usertype)values(p_boxnumber,p_usertype,1);”中表中的列数语句与插入数据的列数不一致。将存储过程pr_dealtestnum放到pr_dealtestnum.sql文件中,使用命令行运行脚本文件,发现MySQL数据库不报错:>mysql-uroot-p'root'-h10.10.10.10-P3306-Ddbtestcallpr_dealtestnum('2344273523',1);ERROR1136(21S01):Columncountdoesn'tmatchvaluecountatrow11212这样,又出现了一个问题。过程中数据插入语句不判断前后列数是否匹配?4.存储过程中写select语句的问题。比如我们还是使用之前的表tb_testnum,创建如下存储过程pr_dealtestnum:;该语句不符合MySQL语法规则,正确的语句应该是“selectcount()intop_boxnumcountfromtb_testnumwhereboxnumber=@p_boxnumber;"将存储过程pr_dealtestnum放到pr_dealtestnum.sql文件中,使用命令行运行脚本文件,发现MySQL数据库不报错:>mysql-uroot-p'root'-h10.10.10.10-P3306-Ddbtestcallpr_dealtestnum('2344273522');+-------------------------+|p_boxnumcount=count(*)|+------------------------+|NULL|+------------------------+1rowinset(0.00sec)+----------------+|p_boxnumcount|+---------------+|NULL|+----------------+1rowinset(0.00sec)QueryOK,0rowsaffected(0.00sec)上面的结果和我们预期的结果有很大的不同。这样,又产生了一个问题。MySQL数据库不是对存储过程中的每条语句都进行了严格的语法检查吗?五、存储过程中取整数值的问题。例如我们创建如下存储过程pr_calculate:p_intnum2)/10*10"赋值给整型变量p_result。将存储过程pr_calculate放在pr_calculate.sql文件中,使用命令行运行脚本文件,结果如下:>mysql-uroot-p'root'-h10.10.10.10-P3306-Ddbtestcallpr_calculate(2,1);+------------+|p_result|+-----------+|3|+------------+1rowinset(0.00sec)QueryOK,0rowsaffected(0.00sec)mysql>callpr_calculate(2,3);+----------+|p_result|+-----------+|5|+----------+1rowinset(0.00sec)QueryOK,0rowsaffected(0.00sec)mysql>callpr_calculate(2,6);+---------+|p_result|+--------+|8|+----------+1rowinset(0.00sec)QueryOK,0rowsaffected(0.00sec)mysql>callpr_calculate(2,9);+--------+|p_result|+--------+|11|+----------+1rowinset(0.00sec)QueryOK,0rowsaffected(0.00sec)mysql>callpr_calculate(2,8);+----------+|p_result|+----------+|10|+--------+1rowinset(0.00sec)QueryOK,0rowsaffected(0.00sec)mysql>callpr_calculate(3,13);+--------+|p_result|+------------+|16|+----------+1rowinset(0.00sec)QueryOK,0rowsaffected(0.00sec)以上输出结果与我们的预期不符,例如对于“callpr_calculate(2,9);”,传入参数后,表达式的值为“setp_result=(2+9)/10*10;”,根据以往的经验,“(2+9)/10*10”的结果应该是10,即“(2+9)/10”应该是1,但是在MySQL中,表达式公式的值为11,这说明在MySQL数据库中,整型变量的计算规则是不一样的。6.“四舍五入”的问题例如直接在MySQL数据库上执行如下语句:mysql>selectconvert(8/6,signed);--+|convert(8/6,signed)|+----------------+|1|+---------------------+1rowinset(0.00sec)mysql>selectconvert(9/6,signed);+-----------------------+|convert(9/6,signed)|+----------------+|2|+--------------------+1rowinset(0.00sec)可以看到因为“8/6”小于1.5,所以四舍五入后的值为1;又因为“9/6”等于1.5,所以四舍五入后的值为2。也可以看出,MySQL数据库在将小数转换为整数的过程中,遵循了“四舍五入”的原则。7.总结MySQL作为流行的开源数据库,已经被众多中小型网站所采用,在数据库市场中占据了25%以上的市场份额。然而,如本文所述,MySQL并不完美。期待MySQL会不断优化,让更多的软件产品使用它。【本文为专栏作家周兆雄原创文章,作者微信公众号:周氏逻辑(logiczhou)】