MySQL Tips【Updating】

一、MySQL中varchar最大長度問題

問題:爲啥大字段能夠建,小字段卻失敗?  mysql

單個varchar(20000)用utf8沒有超過64K,不會轉成text類型,2個呢又超了64K最大單行長度。varchar(30000)用utf8超64K,被轉成text類型,因此沒事。其實第一個建表語句被 "2 warnings"果斷出賣了 

具體的能夠參考這篇:
MySQL中varchar最大長度是多少? sql

http://dinglin.iteye.com/blog/914276 網絡

二、mysql時間相減的問題(bug)

--建立表
mysql> CREATE TABLE mytest (
  t1 datetime,
  t2 datetime
);
Query OK, 0 rows affected
--插入測試記錄
mysql> insert into mytest(t1,t2) values('2013-04-21 16:59:33','2013-04-21 16:59:43');
Query OK, 1 row affected

mysql> insert into mytest(t1,t2) values('2013-04-21 16:59:33','2013-04-21 17:00:33');
Query OK, 1 row affected

mysql> insert into mytest(t1,t2) values('2013-04-21 16:59:33','2013-04-21 17:59:35');
Query OK, 1 row affected
--驗證結果
mysql> select t1,t2,t2-t1 from mytest;
+---------------------+---------------------+-------+
| t1                  | t2                  | t2-t1 |
+---------------------+---------------------+-------+
| 2013-04-21 16:59:33 | 2013-04-21 16:59:43 |    10 |
| 2013-04-21 16:59:33 | 2013-04-21 17:00:33 |  4100 |
| 2013-04-21 16:59:33 | 2013-04-21 17:59:35 | 10002 |
+---------------------+---------------------+-------+
3 rows in set

這個問題2003年就有人在mysql4.0的版本時反饋,但mysql官方並不認爲是bug,由於他們認爲mysql並不支持時間直接相減操做,應該用專用函數處理,因此一直沒有修正。但我認爲這個很容易致使使用錯誤,要麼就直接報錯,要麼顯示正確的結果。函數

要獲得正確的時間相減秒值,有如下3種方法:
一、time_to_sec(timediff(t2, t1)),
二、timestampdiff(second, t1, t2),
三、unix_timestamp(t2) -unix_timestamp(t1)性能

--測試腳本
mysql> select t1,
       t2,
       t2-t1,
       time_to_sec(timediff(t2, t1)) diff1,
       timestampdiff(second, t1, t2) diff2,
       unix_timestamp(t2) -unix_timestamp(t1) diff3
  from mytest;
+---------------------+---------------------+-------+-------+-------+-------+
| t1                  | t2                  | t2-t1 | diff1 | diff2 | diff3 |
+---------------------+---------------------+-------+-------+-------+-------+
| 2013-04-21 16:59:33 | 2013-04-21 16:59:43 |    10 |    10 |    10 |    10 |
| 2013-04-21 16:59:33 | 2013-04-21 17:00:33 |  4100 |    60 |    60 |    60 |
| 2013-04-21 16:59:33 | 2013-04-21 17:59:35 | 10002 |  3602 |  3602 |  3602 |
+---------------------+---------------------+-------+-------+-------+-------+
3 rows in set

from:http://blog.csdn.net/yzsind/article/details/8831429 測試

三、where查詢between和用>=and <=返回值不一致,貌似不管哪一個版本都是這樣:

緣由: 優化

between and 的時候按照bigint去算了,致使後面那個值變成了負數  spa

四、MySQL的varchar定義長度究竟是字節仍是字符

UTF8字符集下:
SQL>create table test(id int auto_increment,name varchar(10),primary key(id));
SQL>insert into test values(null,'1234567890');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'一二三四五六七八九十');
Query OK, 1 row affected (0.00 sec)
SQL>insert into test values(null,'abcdefghig');
Query OK, 1 row affected (0.01 sec)
SQL>insert into test values(null,12345678901);
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>insert into test values(null,'一二三四五六七八九十1');
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>insert into test values(null,'一二三四五六七八九十一');
ERROR 1406 (22001): Data too long for column 'name' at row 1
SQL>select id,name,length(name),char_length(name) from test;
+----+--------------------------------+--------------+-------------------+
 | id | name | length(name) | char_length(name) |
 +----+--------------------------------+--------------+-------------------+
 | 1 | 1234567890 | 10 | 10 |
 | 2 | 一二三四五六七八九十 | 30 | 10 |
 | 3 | abcdefghig | 10 | 10 |
 +----+--------------------------------+--------------+-------------------+
 3 rows in set (0.00 sec)
有此可見,varchar(10) 定義的是字符長度,而length(name) 算的是字節長度,操作系統

 char_length(name)則計算的是字符長度。.net

     那麼varchar可以定義的最大長度是多少呢?這個和你當前所使用的字符集有關。拋開字符,其最大長度爲65535字節(這是最大行大小,由全部列共享),而放在不一樣的字符集下,可以定義的最大長度就會有所不一樣,如UTF8下是21845。聽說MySQL5中varchar的長度也爲字符,而MySQL4中的則爲字節,未經證明,感興趣的有環境能夠本身測下。
     順便補充一下,char數據類型定義的長度也爲字符,其最大長度爲255。
http://ourmysql.com/archives/1286?f=wb

五、如何優化MySQL insert性能

合併數據 + 事務插入,能夠有效減小 SQL 解析時間和網絡IO、事務的頻繁建立。

注意事項:
1. SQL語句是有長度限制,在進行數據合併在同一SQL中務必不能超過SQL長度限制,經過max_allowed_packet配置能夠修改,默認是1M。
2. 事務須要控制大小,事務太大可能會影響執行的效率。MySQL有innodb_log_buffer_size配置項,超過這個值會日誌會使用磁盤數據,這時,效率會有所降低。因此比較好的作法是,在事務大小達到配置項數據級前進行事務提交。

http://blog.jobbole.com/29432/#jtss-tsina

六、關於MySQL count(distinct) 邏輯的一個bug

客戶報告了一個count(distinct)語句返回結果錯誤,實際結果存在值,可是用count(distinct)統計後返回的是0。

緣由:設置了 set tmp_table_size=xxx,但 xxx 去重、歸併排序內存不夠致使排序值被丟棄,進而得不到結果。

解決:set sql_big_tables=on,或者調高上述 size,或者打補丁臨時申請內存再釋放。

完整案例,請見:http://dinglin.iteye.com/blog/1976026

關於MySQL count(distinct) 邏輯的另外一個bug  http://dinglin.iteye.com/blog/1982176

七、MySQL關於timestamp和mysqldump的一個「bug」

說說關於timestamp這個字段類型。
首先,從大小上你能夠看出來,它不是個字符串,其實是一個整型。因此當咱們執行 where c=」 2012-12-14 00:42:45」的時候,須要將其轉換爲整型。這就涉及到轉換規則。也就是說,對於相同的時間戳,在不一樣的時區顯示的結果是不同的。反過來也同樣,相同的字符串,在不一樣的時區解釋下,會獲得不一樣的時間戳。
咱們來看一下整個mysqldump的結果。在文件頭部,能夠看到
/*!40103 SET TIME_ZONE='+00:00' */; 字樣,說明mysqldump在默認狀況下,是按’+00:00’(中時區).
而mysql客戶端的默認值呢:
mysql> select @@time_zone;
+-------------+
| @@time_zone |
+-------------+
| SYSTEM      |
+-------------+
這個SYSTEM表示MySQL取操做系統的默認時區,所以是東8區。

所以會形成:

mysql> select * from tb;
+---------------------+
| c                   |
+---------------------+
| 2012-12-14 00:42:45 |
+---------------------+
1 row in set (0.00 sec)
 
二、dump「出錯」
  mysqldump   -Srun/mysql.sock -uroot   test tb   --where='c="2012-12-14 00:42:45"' | grep INSERT
返回爲空,也就是說導不到數據。

解決方案:

(1) mysqldump  --tz-utc=0 -Srun/mysql.sock -uroot   test tb   --where='c="2012-12-14 00:42:45"'  |grep INSERT 

        --tz-utc=0 參數去掉前面的設置時區的動做。

(2) --where='c= from_unixtime(1355416965)' 注意順序,關係到是否能走索引。

完整案例請見這裏:http://dinglin.iteye.com/blog/1747685

八、mysql left( right ) join 使用 on 與 where 篩選的差別

drop table if EXISTS A;
CREATE TABLE A (
  ID int(1) NOT NULL,
  PRIMARY KEY  (ID)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

drop table if EXISTS B;
CREATE TABLE B (
  ID int(1) NOT NULL,
  PRIMARY KEY  (ID)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

insert into A values ( 1 );
insert into A values ( 2 );
insert into A values ( 3 );
insert into A values ( 4 );
insert into A values ( 5 );
insert into A values ( 6 );

insert into B values ( 1 );
insert into B values ( 2 );
insert into B values ( 3 );

-- 語句1
select A.ID as AID, B.ID as BID from A left join B on A.ID = B.ID where B.ID<3  
-- 語句2
select A.ID as AID, B.ID as BID from A left join B on A.ID = B.ID and B.ID<3

語句 1 的查詢結果:

語句 2 的查詢結果爲:

緣由:上述兩個語句結果不同的緣由是SQL語法順序和其執行順序沒啥關係,其執行順序爲:

FROM→ON→JOIN→WHERE→GROUP BY→HAVING→SELECT→DISTINCT→ORDER BY→LIMIT

(能夠理解爲 select 須要在全部的非冪等操做執行完了以後才執行,不然 select 出來的結果就會有問題)

所以ON與where的使用必定要注意場所:

    (1):ON後面的篩選條件主要是針對的是關聯表【而對於主表刷選條件不適用】。

                即主表條件在on後面時附表只取知足主表帥選條件的值、而主表仍是取整表。

    (2):對於主表的篩選條件應放在where後面,不該該放在ON後面

    (3):對於關聯表咱們要區分對待。若是是要條件查詢後才鏈接應該把查詢件放置於ON後。

              若是是想再鏈接完畢後才篩選就應把條件放置於where後面

    (4): 對於關聯表咱們其實能夠先作子查詢再作join,因此第二個sql等價於:

select  A.ID as AID, B1.ID as BID
from A left join  ( select B.ID from B  where B.ID <3 )B1 on A.ID = B1.ID

以上全在mysql5.1上測試過

完整案例請見這裏:http://xianglp.iteye.com/blog/868957

相關文章
相關標籤/搜索