新聞中心
近期,筆者在做MySQL腳本的移植和測(cè)試工作。在此過(guò)程中,發(fā)現(xiàn)了MySQL數(shù)據(jù)庫(kù)所存在的一些有待優(yōu)化的地方,特寫(xiě)下此文,供相關(guān)項(xiàng)目的開(kāi)發(fā)人員參考。

站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到南部網(wǎng)站設(shè)計(jì)與南部網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:做網(wǎng)站、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名申請(qǐng)、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋南部地區(qū)。
一、存儲(chǔ)過(guò)程中所使用的參數(shù)名錯(cuò)誤的問(wèn)題
例如,在MySQL數(shù)據(jù)庫(kù)中新建如下表tb_testnum:
- drop table if exists tb_testnum;
- create table tb_testnum
- (
- boxnumber varchar(30) not null,
- usertype int not null
- );
- create unique index idx1_tb_testnum on tb_testnum(boxnumber);
同時(shí),創(chuàng)建如下存儲(chǔ)過(guò)程pr_dealtestnum:
- drop procedure if exists pr_dealtestnum;
- delimiter //
- create procedure pr_dealtestnum
- (
- in p_boxnumber varchar(30)
- )
- pr_dealtestnum_label:begin
- declare p_boxnumcount int;
- select count(*) into p_boxnumcount from tb_testnum where boxnumber=p_boxnumbe;
- select p_boxnumcount;
- leave pr_dealtestnum_label;
- end;
- //
- delimiter ;
- select 'create procedure pr_dealtestnum ok';
注意,“select count(*) into p_boxnumcount from tb_testnum where boxnumber=p_boxnumbe;”語(yǔ)句中的參數(shù)“p_boxnumbe”與輸入?yún)?shù)“p_boxnumber”不一樣(少了一個(gè)r),該參數(shù)未在存儲(chǔ)過(guò)程中定義。
將存儲(chǔ)過(guò)程pr_dealtestnum放到pr_dealtestnum.sql文件中,使用命令行運(yùn)行該腳本文件,發(fā)現(xiàn)MySQL數(shù)據(jù)庫(kù)居然不報(bào)錯(cuò):
- > mysql -uroot -p'root' -h10.10.10.10 -P3306 -Ddbtest
- create procedure pr_dealtestnum ok
- create procedure pr_dealtestnum ok
接著,在MySQL數(shù)據(jù)庫(kù)上調(diào)用該存儲(chǔ)過(guò)程時(shí)報(bào)錯(cuò),提示“p_boxnumbe”不存在:
- mysql> call pr_dealtestnum('2344273522');
- ERROR 1054 (42S22): Unknown column 'p_boxnumbe' in 'where clause'
這樣,問(wèn)題就出現(xiàn)了,難道MySQL數(shù)據(jù)庫(kù)對(duì)存儲(chǔ)過(guò)程中所使用的參數(shù)名的檢查不嚴(yán)格?
二、存儲(chǔ)過(guò)程中所使用的參數(shù)名前面存在多余符號(hào)的問(wèn)題
這個(gè)問(wèn)題和***個(gè)問(wèn)題類似,只是“參數(shù)名錯(cuò)誤”變成了“在參數(shù)名前面有多余的符號(hào)”。
例如,我們還是使用問(wèn)題一中的表tb_testnum,并在表中插入數(shù)據(jù):
- insert into tb_testnum(boxnumber,usertype) values('2344273522',1);11
同時(shí),創(chuàng)建如下存儲(chǔ)過(guò)程pr_dealtestnum:
- drop procedure if exists pr_dealtestnum;
- delimiter //
- create procedure pr_dealtestnum
- (
- in p_boxnumber varchar(30)
- )
- pr_dealtestnum_label:begin
- declare p_boxnumcount int;
- select count(*) into p_boxnumcount from tb_testnum where boxnumber=@p_boxnumber;
- select p_boxnumcount;
- leave pr_dealtestnum_label;
- end;
- //
- delimiter ;
- select 'create procedure pr_dealtestnum ok';
注意,“select count(*) into p_boxnumcount from tb_testnum where boxnumber=@p_boxnumber;”語(yǔ)句中的參數(shù)“@p_boxnumber”是在輸入?yún)?shù)“p_boxnumber”的前面添加了@符號(hào)。
將存儲(chǔ)過(guò)程pr_dealtestnum放到pr_dealtestnum.sql文件中,使用命令行運(yùn)行該腳本文件,發(fā)現(xiàn)MySQL數(shù)據(jù)庫(kù)居然不報(bào)錯(cuò):
- > mysql -uroot -p'root' -h10.10.10.10 -P3306 -Ddbtest
- create procedure pr_dealtestnum ok
- create procedure pr_dealtestnum ok123123
接著,在MySQL數(shù)據(jù)庫(kù)上調(diào)用該存儲(chǔ)過(guò)程時(shí)無(wú)報(bào)錯(cuò),但是輸出的結(jié)果不正確:
- mysql> call pr_dealtestnum('2344273522');
- +---------------+
- | p_boxnumcount |
- +---------------+
- | 0 |
- +---------------+
- 1 row in set (0.00 sec)
- Query OK, 0 rows affected (0.00 sec)
因?yàn)槲覀冊(cè)谇懊嬉呀?jīng)向表tb_testnum中插入了一條數(shù)據(jù),所以正確的輸出應(yīng)該是1,而不是0。
我們將“select count(*) into p_boxnumcount from tb_testnum where boxnumber=@p_boxnumber;”語(yǔ)句中的“@p_boxnumber”中的@符號(hào)去掉,再放到MySQL數(shù)據(jù)庫(kù)中運(yùn)行,發(fā)現(xiàn)執(zhí)行“call pr_dealtestnum(‘2344273522’);”之后輸出的結(jié)果就是正確的了。
這也說(shuō)明了MySQL數(shù)據(jù)庫(kù)對(duì)存儲(chǔ)過(guò)程中所使用的參數(shù)名的檢查不嚴(yán)格。
三、存儲(chǔ)過(guò)程中向表中插入多余數(shù)據(jù)的問(wèn)題
例如,我們還是使用前面兩個(gè)問(wèn)題中的表tb_testnum,如果直接向表中插入多余的數(shù)據(jù),則MySQL數(shù)據(jù)庫(kù)會(huì)報(bào)錯(cuò):
- mysql> insert into tb_testnum(boxnumber,usertype) values('2344273523',1,1);
- ERROR 1136 (21S01): Column count doesn't match value count at row 1
報(bào)錯(cuò)的原因是表tb_testnum只有兩列,但是欲向其中插入三列數(shù)據(jù)。
接著,創(chuàng)建如下存儲(chǔ)過(guò)程pr_dealtestnum:
- drop procedure if exists pr_dealtestnum;
- delimiter //
- create procedure pr_dealtestnum
- (
- in p_boxnumber varchar(30),
- in p_usertype int
- )
- pr_dealtestnum_label:begin
- insert into tb_testnum(boxnumber,usertype) values(p_boxnumber,p_usertype,1);
- leave pr_dealtestnum_label;
- end;
- //
- delimiter ;
- select 'create procedure pr_dealtestnum ok';
注意,“insert into tb_testnum(boxnumber,usertype) values(p_boxnumber,p_usertype,1);”語(yǔ)句中表的列數(shù)和插入數(shù)據(jù)的列數(shù)不一致。
將存儲(chǔ)過(guò)程pr_dealtestnum放到pr_dealtestnum.sql文件中,使用命令行運(yùn)行該腳本文件,發(fā)現(xiàn)MySQL數(shù)據(jù)庫(kù)居然不報(bào)錯(cuò):
- > mysql -uroot -p'root' -h10.10.10.10 -P3306 -Ddbtest
- create procedure pr_dealtestnum ok
- create procedure pr_dealtestnum ok
然后,在MySQL數(shù)據(jù)庫(kù)上調(diào)用該存儲(chǔ)過(guò)程時(shí)報(bào)錯(cuò),提示列不匹配:
- mysql> call pr_dealtestnum('2344273523',1);
- ERROR 1136 (21S01): Column count doesn't match value count at row 11212
這樣,又一個(gè)問(wèn)題出現(xiàn)了,難道MySQL數(shù)據(jù)庫(kù)對(duì)存儲(chǔ)過(guò)程中的數(shù)據(jù)插入語(yǔ)句不判斷前后列數(shù)是否匹配?
四、存儲(chǔ)過(guò)程中的select語(yǔ)句的編寫(xiě)問(wèn)題
例如,我們還是使用前面的表tb_testnum,并創(chuàng)建如下存儲(chǔ)過(guò)程pr_dealtestnum:
- drop procedure if exists pr_dealtestnum;
- delimiter //
- create procedure pr_dealtestnum
- (
- in p_boxnumber varchar(30)
- )
- pr_dealtestnum_label:begin
- declare p_boxnumcount int;
- select p_boxnumcount=count(*) from tb_testnum where boxnumber=p_boxnumber;
- select p_boxnumcount;
- leave pr_dealtestnum_label;
- end;
- //
- delimiter ;
- select 'create procedure pr_dealtestnum ok';
注意,“select p_boxnumcount=count() from tb_testnum where boxnumber=p_boxnumber;”語(yǔ)句是不符合MySQL語(yǔ)法規(guī)則的,正確的語(yǔ)句應(yīng)該是“select count() into p_boxnumcount from tb_testnum where boxnumber=@p_boxnumber;”。
將存儲(chǔ)過(guò)程pr_dealtestnum放到pr_dealtestnum.sql文件中,使用命令行運(yùn)行該腳本文件,發(fā)現(xiàn)MySQL數(shù)據(jù)庫(kù)居然不報(bào)錯(cuò):
- > mysql -uroot -p'root' -h10.10.10.10 -P3306 -Ddbtest
- create procedure pr_dealtestnum ok
- create procedure pr_dealtestnum ok123123
然后,在MySQL數(shù)據(jù)庫(kù)上調(diào)用該存儲(chǔ)過(guò)程,輸出結(jié)果如下:
- mysql> call pr_dealtestnum('2344273522');
- +------------------------+
- | p_boxnumcount=count(*) |
- +------------------------+
- | NULL |
- +------------------------+
- 1 row in set (0.00 sec)
- +---------------+
- | p_boxnumcount |
- +---------------+
- | NULL |
- +---------------+
- 1 row in set (0.00 sec)
- Query OK, 0 rows affected (0.00 sec)
以上結(jié)果與我們預(yù)期的結(jié)果相差甚遠(yuǎn)。
這樣,又一個(gè)問(wèn)題出現(xiàn)了,難道MySQL數(shù)據(jù)庫(kù)對(duì)存儲(chǔ)過(guò)程中的每條語(yǔ)句不作嚴(yán)格的語(yǔ)法校驗(yàn)?
五、存儲(chǔ)過(guò)程中取整數(shù)值的問(wèn)題
例如,我們創(chuàng)建如下存儲(chǔ)過(guò)程pr_calculate:
- drop procedure if exists pr_calculate;
- delimiter //
- create procedure pr_calculate
- (
- in p_intnum1 int,
- in p_intnum2 int
- )
- pr_calculate_label:begin
- declare p_result int;
- set p_result = (p_intnum1+p_intnum2)/10*10;
- select p_result;
- leave pr_calculate_label;
- end;
- //
- delimiter ;
- select 'create procedure pr_calculate ok';
在此存儲(chǔ)過(guò)程中,我們想把“(p_intnum1+p_intnum2)/10*10”結(jié)果賦給整型變量p_result。
將存儲(chǔ)過(guò)程pr_calculate放到pr_calculate.sql文件中,使用命令行運(yùn)行該腳本文件,結(jié)果如下:
- > mysql -uroot -p'root' -h10.10.10.10 -P3306 -Ddbtest
- create procedure pr_calculate ok
- create procedure pr_calculate ok123123
然后,在MySQL數(shù)據(jù)庫(kù)上調(diào)用該存儲(chǔ)過(guò)程,輸出結(jié)果如下:
- mysql> call pr_calculate(2,1);
- +----------+
- | p_result |
- +----------+
- | 3 |
- +----------+
- 1 row in set (0.00 sec)
- Query OK, 0 rows affected (0.00 sec)
- mysql> call pr_calculate(2,3);
- +----------+
- | p_result |
- +----------+
- | 5 |
- +----------+
- 1 row in set (0.00 sec)
- Query OK, 0 rows affected (0.00 sec)
- mysql> call pr_calculate(2,6);
- +----------+
- | p_result |
- +----------+
- | 8 |
- +----------+
- 1 row in set (0.00 sec)
- Query OK, 0 rows affected (0.00 sec)
- mysql> call pr_calculate(2,9);
- +----------+
- | p_result |
- +----------+
- | 11 |
- +----------+
- 1 row in set (0.00 sec)
- Query OK, 0 rows affected (0.00 sec)
- mysql> call pr_calculate(2,8);
- +----------+
- | p_result |
- +----------+
- | 10 |
- +----------+
- 1 row in set (0.00 sec)
- Query OK, 0 rows affected (0.00 sec)
- mysql> call pr_calculate(3,13);
- +----------+
- | p_result |
- +----------+
- | 16 |
- +----------+
- 1 row in set (0.00 sec)
- Query OK, 0 rows affected (0.00 sec)
以上輸出結(jié)果與我們的預(yù)期不相符,如對(duì)于“call pr_calculate(2,9);”,參數(shù)傳進(jìn)去之后,表達(dá)式的值為“set p_result = (2+9)/10*10;”,按照以往的經(jīng)驗(yàn),“(2+9)/10*10”的結(jié)果應(yīng)該為10,即“(2+9)/10”應(yīng)該為1,但是在MySQL中,該表達(dá)式的值卻為11。
這說(shuō)明了在MySQL數(shù)據(jù)庫(kù)中,對(duì)于整型變量的計(jì)算規(guī)則有所不同。
六、“四舍五入”的問(wèn)題
例如,直接在MySQL數(shù)據(jù)庫(kù)上執(zhí)行如下語(yǔ)句:
- mysql> select convert(8/6, signed);
- +----------------------+
- | convert(8/6, signed) |
- +----------------------+
- | 1 |
- +----------------------+
- 1 row in set (0.00 sec)
- mysql> select convert(9/6, signed);
- +----------------------+
- | convert(9/6, signed) |
- +----------------------+
- | 2 |
- +----------------------+
- 1 row in set (0.00 sec)
可以看到,因?yàn)椤?/6”小于1.5,所以對(duì)其取整后的值就為1;而因?yàn)椤?/6”等于1.5,所以對(duì)其取整后的值就為2。這也可以看出,在將小數(shù)轉(zhuǎn)換為整數(shù)的過(guò)程中,MySQL數(shù)據(jù)庫(kù)遵循的是“四舍五入”的原則。
七、總結(jié)
MySQL作為一款廣受歡迎的開(kāi)源數(shù)據(jù)庫(kù),目前已被很多中小網(wǎng)站采用,在數(shù)據(jù)庫(kù)市場(chǎng)上占據(jù)了25%以上的市場(chǎng)份額。但是,如在本文中所描述的那樣,MySQL也并非是十全十美的。
期待MySQL會(huì)不斷進(jìn)行優(yōu)化,讓更多的軟件產(chǎn)品來(lái)使用它。
【本文是專欄作者周兆熊的原創(chuàng)文章,作者微信公眾號(hào):周氏邏輯(logiczhou)】
文章題目:在測(cè)試MySQL腳本時(shí)所遇到的問(wèn)題
標(biāo)題路徑:http://fisionsoft.com.cn/article/cceoojg.html


咨詢
建站咨詢
