問題:爲啥大字段能夠建,小字段卻失敗? 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> 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 測試
緣由: 優化
between and 的時候按照bigint去算了,致使後面那個值變成了負數 spa
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
合併數據 + 事務插入,能夠有效減小 SQL 解析時間和網絡IO、事務的頻繁建立。
注意事項:
1. SQL語句是有長度限制,在進行數據合併在同一SQL中務必不能超過SQL長度限制,經過max_allowed_packet配置能夠修改,默認是1M。
2. 事務須要控制大小,事務太大可能會影響執行的效率。MySQL有innodb_log_buffer_size配置項,超過這個值會日誌會使用磁盤數據,這時,效率會有所降低。因此比較好的作法是,在事務大小達到配置項數據級前進行事務提交。
http://blog.jobbole.com/29432/#jtss-tsina
客戶報告了一個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
說說關於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
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