MySQL的那些事兒

1、MySQL如何將select結果保存到一個數據庫表中:

相關參考:MySql將查詢結果插入到另外一張表

2、MySQL長事務導致的Table Metadata Lock:

現象:MySQL數據庫表添加字段時卡死,報錯爲:Waiting for table metadata lock,此時數據庫表無法刪除和修改,只能read,這是因爲MySQL出現了死鎖(?)

解決方法:先執行 show processlist,查看當前那些id出現了上述錯誤,如下圖:

然後執行kill id,對於上圖就是kill 605546;

接着執行select * from information_schema.innodb_trx\G,結果如下圖:

然後執行kill 562347;最後把數據庫表刪除即可(這一步不做,只要執行kill 562347就差不多了)

3、  MySQL提示Please DISCARD the tablespace before IMPORT:

這個是表刪除不乾淨導致的,目錄刪除了 但是物理文件還在,可以使用show global variables like "%datadir%";查看mysql數據庫文件保存的位置,然後刪除 :表名.frm 表名.ibd;這兩個文件 即可

4、MySQL報“open too many files”錯誤的解決方法:

相關參考:How to permanently raise ulimit 'open files' and MySQL 'open_files_limit'

對於centOS,下面測試可行:

Hi, I have a CentOS 7 / MySQL 5.6 server and I tried all suggestions i found online, and still cat /proc/xxxx/limits showed 1024 max open files. (where X is the pid from the mysqld process. The missing thing was a .configuration setting in the mysql service.

I did the following:

Go to services directory:
cd /etc/systemd/system/

Remove the symlink:
rm mysql.service

Copy service to services directory (so it won't be overwritten by any upgrade):
cp /usr/lib/systemd/system/mysqld.service mysqld.service

In the Service section add LimitNOFILE=1024000.

In my case it's now:

[Service]
User=mysql
Group=mysql
LimitNOFILE=1024000

Restart.

limits are now:
[root@dev system]# cat /proc/5981/limits
Max open files 1024000 1024000 files

 

5、MySQL 如何查看錶的存儲引擎:

show create table +表名;

6、如何插入包含datetime類型字段的記錄:

相關參考:MySQL: Insert datetime into other datetime field

According to MySQL documentation, you should be able to just enclose that datetime string in single quotes, ('YYYY-MM-DD HH:MM:SS') and it should work.

 

7、MySQL數據導入導出指令:

a、導出.sql文件:

(1)mysqldump,

如:mysqldump -u {username} -p  --databases {db_name} -t --tables {table_name} --where='{query_condition}'> test.sql

詳細用法請參考MySQL mysqldump數據導出詳解

mysqldump指令各個參數的說明:mysqldump數據導出詳解(超詳細)

(2) 

SELECT * INTO OUTFILE 'data_path.sql' from table where id<100000

b、導入.sql文件:source

如:mysql客戶端登錄後,先選擇數據庫:use {db_name};source /path_to_sql/test.sql

 

8、MySQL可以使用limit關鍵字實現分頁查詢:

詳細參考:詳解MySQL的limit用法和分頁查詢語句的性能分析

 

9、win7下啓用MySQL服務:

當按照官網的教程,使用指令:MySQL安裝路徑\bin\mysqld或者使用網上教程:切換到bin路徑下執行net start mysql均無法啓動MySQL服務時,可以在win7的服務中手動啓動MySQL服務,如下圖:

 

10、在Ubuntu 16.04下,當MySQL被動更新了版本時(如使用apt-get install安裝Plibmysqlclient-dev庫【Python的mysql-python包依賴該庫】),比如從5.7版本更新爲8.0版本,此時連上數據庫(使用root賬戶)後執行指令,如show databases,會出現如下錯誤:

解決方法:

執行以下指令:mysql_upgrade -u root -p ,輸入root賬戶的密碼即可。

 

11、數據庫髒讀、幻讀、不可重複讀問題:

相關參考:MySQL的四種事務隔離級別

另外的參考:數據庫事務隔離級別-- 髒讀、幻讀、不可重複讀(清晰解釋)

 

12、MySQL集羣:

先挖坑,再補充。

 

13、MySQL存儲引擎相關:

相關參考:MySQL存儲引擎中的MyISAM和InnoDB區別詳解

MyISAM:每個MyISAM在磁盤上存儲成三個文件。第一個文件的名字以表的名字開始,擴展名指出文件類型。.frm文件存儲表定義。數據文件的擴展名爲.MYD (MYData)。索引文件的擴展名是.MYI (MYIndex)。
InnoDB:所有的表都保存在同一個數據文件中(也可能是多個文件,或者是獨立的表空間文件),InnoDB表的大小隻受限於操作系統文件的大小,一般爲2GB。

14、MySQL查詢執行過程:

15、MySQL索引:

(1)爲什麼需要索引?

根本原因是避免進行全表掃描(或者說減少需要掃描的行數),可以類比二分查找,可以快速定位所需數據,提高查詢速度。

(2)MySQL有哪些索引?

a、B+Tree索引(類似於B-Tree索引),每一個葉子節點包含指向下一個葉子節點的指針;

b、哈希索引,基於散列表(Hash table)實現,存儲引擎對所有的索引列計算一個哈希值,目前只有Memory引擎顯示支持哈希索引;

c、空間索引(spatial index),MyISAM引擎支持,用於存儲地理數據;

d、全文索引(Full Text Index),MyISAM引擎支持;

(3)索引的缺點?

當數據量很大的時候,索引可能會引起性能下降,而且存儲索引也會佔用一定存儲空間;

16、MySQL基本操作:

(1)已有數據庫表增加字段:

ALTER TABLE `user`
ADD COLUMN `username`  varchar(20) NULL DEFAULT '' COMMENT '用戶名' AFTER `phone`,
ADD COLUMN `create_at`  datetime NULL COMMENT '創建時間' AFTER `username`;

COLUMN 可以省略,AFTER表示添加在某個字段後面,沒有則添加在最後面

(2)一條update語句更新多條記錄的一個字段值:執行一條sql語句update多條記錄實現思路

(3)insert多條記錄條目時遇到unique key重複時:

使用insert ignore或者insert on duplicate key update:“INSERT IGNORE” vs “INSERT … ON DUPLICATE KEY UPDATE”

(4)join的用法:MySQL的JOIN(一):用法

(5)varchar和text的區別:Difference between VARCHAR and TEXT in mysql [closed]

(6)刪除和添加字段:MySQL添加字段和刪除字段

(7)獲取字段的排序值:MySQL - Get row number on select

(8)offset和limit的用法:Mysql limit offset用法舉例

例如:select * from student limit 9,4,表示從student表的10行開始取4行,即返回表中的10-13行

(9)使用聯表join進行update:How to do 3 table JOIN in UPDATE query?

例如:

UPDATE TABLE_A a 
    JOIN TABLE_B b ON a.join_col = b.join_col AND a.column_a = b.column_b 
    JOIN TABLE_C c ON [condition]
SET a.column_c = a.column_c + 1

(10)字符串拼接函數CONCAT:

使用方法:CONCAT(str1,str2,…) 

返回結果爲連接參數產生的字符串。如有任何一個參數爲NULL ,則返回值爲 NULL。

(11)GROUP_CONCAT函數:

把查詢結果的行用逗號作爲分隔符拼接起來;

(12)MySQL字符串操作函數:

常用的有replace(string, src_part, dst_part), length(str), locate(substr, str), substring(str, pos), left(string, length), right(string, length)等......

demo:

update `article` set content = concat(replace(content, substring(content, locate('haha', content)-11), ''), '"') where status = 1 and name = 'hehe' and content like '%haha%';

相關參考: MySQL字符串函數:字符串截取

(13) 修改字段定義:

ALTER TABLE table_name MODIFY COLUMN new-column-definition;

當需要修改字段名稱時使用change;當需要修改字段類型時使用modify

相關參考:mysql中alter語句中change和modify的區別

(14)having的用法:mysql having的用法

17、MySQL按照時間查詢相關記錄:

(1)如何查詢今天的數據:

select * from 表名 where to_days(時間字段名) = to_days(now());

(2)如何查詢最近7天的數據:

SELECT * FROM 表名 where DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= date(時間字段名);

具體可參考:MySQL中, 如何查詢某一天, 某一月, 某一年的數據

 

18、MySQL查詢性能分析:

(1)首先要explain一下查詢語句,explain結果各個字段的含義可以參考:【踩坑】MySQL時間索引失效

(2)可以結合《高性能MySQL》中查詢優化的內容加深理解。

(3)索引命中相關:注意不要對索引字段使用not in,!=,否則會導致索引失效,進行全表掃描,這個可以結合索引的原理來理解。

 

19、MySQL的json類型相關:

相關參考:MySQL 5.7 JSON 實現簡介

最好還是參考MySQL官方文檔。

 

20、MySQL導入csv文件:

(1)mysql登錄的時候要加上--local-infile

(2)登錄後執行:

load data local infile 'csv_path/your_csv_file.csv' into table table_name 

character set UTF8

fields terminated by ',' enclosed by '"' lines terminated by '\n' ignore 1 rows (field_1, field_2, ...);

注:使用ignore 1 rows是因爲csv第一行是字段名

參數說明:
into outfile ‘導出的目錄和文件名’ 
指定導出的目錄和文件名

fields terminated by ‘字段間分隔符’ 
定義字段間的分隔符

optionally enclosed by ‘字段包圍符’ 
定義包圍字段的字符(數值型字段無效)

lines terminated by ‘行間分隔符’ 
定義每行的分隔符 

(3)導入遇到的權限問題,secure_file_priv,具體參考:How should I tackle --secure-file-priv in MySQL?mac__MySQL導出數據遇到secure-file-priv問題的解決方法

相關參考:How to import CSV file to MySQL tableMySQL import csv file ERROR 13 (HY000): Can't get stat of /path/file.csv (Errcode: 2)MYSQL import data from csv using LOAD DATA INFILE

 

21、mysql導出csv文件:

select 'order_id','product_name','qty'
union all
SELECT order_id,product_name,qty
FROM orders
WHERE foo = 'bar'
INTO OUTFILE '/var/lib/mysql-files/orders.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';

具體參考:How to output MySQL query results in CSV format? 

 

22、MySQL需要支持emoji表情:

解決方案:數據庫字符集需要設置爲utf8mb4,同時客戶端連接(代碼中)也要charset爲utf8mb4

原因分析:utf8一個字符最多3字節,而utf8mb4則擴展到一個字符最多能有4字節

具體參考: MySQL修改字符集爲utf8mb4以支持 emoji 表情符號

 

23、MySQL的timestamp詳解:

生產環境中部署着各種版本的MySQL,包括MySQL 5.5/5.6/5.7三個大版本和N個小版本,由於MySQL在向上兼容性較差,導致相同SQL在不同版本上表現各異,下面從幾個方面來詳細介紹時間戳數據類型。

 

時間戳數據存取

  在MySQL上述三個大版本中,默認時間戳(Timestamp)類型的取值範圍爲'1970-01-01 00:00:01' UTC 至'2038-01-19 03:14:07' UTC,數據精確到秒級別,該取值範圍包含約22億個數值,因此在MySQL內部使用4個字節INT類型來存放時間戳數據:

    1、在存儲時間戳數據時,先將本地時區時間轉換爲UTC時區時間,再將UTC時區時間轉換爲INT格式的毫秒值(使用UNIX_TIMESTAMP函數),然後存放到數據庫中。

    2、在讀取時間戳數據時,先將INT格式的毫秒值轉換爲UTC時區時間(使用FROM_UNIXTIME函數),然後再轉換爲本地時區時間,最後返回給客戶端。

 

  在MySQL 5.6.4及之後版本,可以將時間戳類型數據最高精確微秒(百萬分之一秒),數據類型定義爲timestamp(N),N取值範圍爲0-6,默認爲0,如需要精確到毫秒則設置爲Timestamp(3),如需要精確到微秒則設置爲timestamp(6),數據精度提高的代價是其內部存儲空間的變大,但仍未改變時間戳類型的最小和最大取值範圍。

時間戳字段定義

  時間戳字段定義主要影響兩類操作:

  1、插入記錄時,時間戳字段包含DEFAULT CURRENT_TIMESTAMP,如插入記錄時未指定具體時間數據則將該時間戳字段值設置爲當前時間

  2、更新記錄時,時間戳字段包含ON UPDATE CURRENT_TIMESTAMP,如更新記錄時未指定具體時間數據則將該時間戳字段值設置爲當前時間

  PS1:CURRENT_TIMESTAMP表示使用CURRENT_TIMESTAMP()函數來獲取當前時間,類似於NOW()函數

  根據上面兩類操作,時間戳列可以有四張組合定義,其含義分別爲:

  1、當字段定義爲timestamp,表示該字段在插入和更新時都不會自動設置爲當前時間。

  2、當字段定義爲timestamp DEFAULT CURRENT_TIMESTAMP,表示該字段僅在插入且未指定值時被賦予當前時間,再更新時且未指定值時不做修改。

  3、當字段定義爲timestamp ON UPDATE CURRENT_TIMESTAMP,表示該字段在插入且未指定值時被賦值爲"0000-00-00 00:00:00",在更新且未指定值時更新爲當前時間。

  4、當字段定義爲timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,表示該字段在插入或更新時未指定值,則被賦值爲當前時間。

  PS1:在MySQL中執行的建表語句和最終表創建語句會存在差異,建議使用SHOW CREATE TABLE TB_XXX獲取已創建表的建表語句。

時間戳類型使用建議

  1、在只關心數據最後更新時間的情況下,建議將時間戳列定義爲TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;

  2、在關心創建時間和更新時間的情況下,建議將更新時間設置爲時間戳字段,將創建時間定義爲DAETIME 或 TIMESTAMP DEFAULT '0000-00-00 00:00:00',並在插入記錄時顯式指定創建時間;

  3、建議在表中只定義單個時間戳列,並顯式定義DEFAULT 和 ON UPDATE屬性;

  4、雖然在MySQL中可以對時間戳字段賦值或更新,但建議僅在必要的情況下對時間戳列進行顯式插入和更新;

  5、建議將time_zone參數設置爲system外的值,如中國地區服務器設置爲'+8:00';

  6、建議將MySQL線下測試版本和線上生產版本保持一致。

具體參考:細說MySQL的時間戳(Timestamp)類型mysql之TIMESTAMP(時間戳)用法詳解

 

24、mysql設置group_concat長度:

默認是1024字節,設置方法如下:

SET GLOBAL group_concat_max_len=102400;
SET SESSION group_concat_max_len=102400;

可參考:MYSQL中group_concat有長度限制!默認1024

25、MySQL用戶管理:

(1)創建用戶:

CREATE USER 'username'@'host' IDENTIFIED BY 'password';

(2)數據庫表訪問授權:

GRANT privileges ON databasename.tablename TO 'username'@'host';

(3)撤銷訪問權限:

REVOKE privilege ON databasename.tablename FROM 'username'@'host';

(4)更改用戶密碼:

SET PASSWORD FOR 'username'@'host' = PASSWORD('newpassword');

(5)刪除用戶:

DROP USER 'username'@'host';

相關參考:MySQL創建用戶與授權

26、MySQL的json相關函數:

請參考:MySQL JSON數據類型操作

27、MySQL字符串處理函數:

時間轉字符串:date_format(now(), '%Y-%m-%d');  字符串轉時間:str_to_date('2016-01-02', '%Y-%m-%d %H'); 

相關參考:MySQL日期 字符串 時間戳互轉

28、Incorrect string value: '\xF0\x9F\x8E\xB6\xF0\x9F…' MySQL客戶端sql語句emoji問題:

解決方法:SET NAMES utf8mb4; 

相關參考:Incorrect string value: '\xF0\x9F\x8E\xB6\xF0\x9F…' MySQL

29、MySQL的IFNULL, NULLIF,ISNULL:

請參考:MySql 裏的IFNULL、NULLIF和ISNULL用法

30、MySQL client的SQL語句包含unicode字符時(如\u00e4),在查詢時like後面的字符串,應使用4個反斜槓,即應該用'\\\\u00e4', 而其他則用2個反斜槓,即'\\u00e4',例如:

select name from user where name like '%\\\\u00e4%';

update user set name = '\\u00e4hehe' where name like '%\\\\u00e4%';

相關參考:MySQL: Querying for unicode entities

31、索引過長問題:

請參考:索引長度過長 ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

32. MySQL join相關:

(1)一般用法是: select a.col1, ..., a.colm, b.col1, ..., b.coln from a join b on a.id = b.id where a.num > 1000,該sql先根據join表的條件(a.id = b.id)和join類型(inner join)得到聯表後的中間表,該過程又叫匹配階段,然後根據where對中間表進行filter,得到最後返回的查詢結果

(2)join的實現原理

join的實現是採用Nested Loop Join算法,就是通過驅動表的結果集作爲循環基礎數據,然後一條一條的通過該結果集中的數據作爲過濾條件到下一個表中查詢數據,然後合併結果。如果有多個join,則將前面的結果集作爲循環數據,再一次作爲循環條件到後一個表中查詢數據

(3)join的類型有inner join(也即join,inner爲默認缺省), left join(也即left outer join), right join

(4)不同的類型主要區別是聯表時的base不同,導致中間表的大小不一樣: 假設tb_a有M行,tb_b有N行, 對於tb_a left join tb_b on tb_a.id = tb_b.id,則聯表得到的大表的記錄行數範圍爲[M, M * N],而如果改爲right join, 聯表得到的大表的記錄行數範圍爲[N, N * M], 而如果爲inner join,則聯表得到的大表的記錄行數範圍爲[0, min{M, N}];這也是一般小表join大表做法的來由

(5)join語句的優化原則

a.用小結果集驅動大結果集,將篩選結果小的表首先連接,再去連接結果集比較大的表,儘量減少join語句中的Nested Loop的循環總次數;

b.優先優化Nested Loop的內層循環(也就是最外層的Join連接),因爲內層循環是循環中執行次數最多的,每次循環提升很小的性能都能在整個循環中提升很大的性能;

c.對被驅動表的join字段上建立索引

d.當被驅動表的join字段上無法建立索引的時候,設置足夠的Join Buffer Size

(6)相關參考:MySQL實戰技巧-1:Join的使用技巧和優化Mysql Join語法以及性能優化

 

33.如何確定一個表有多少行記錄?(geek)

請使用explain: explain select count(1) from test_tb; 否則會全表掃描

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章