導致結果:
連線數過多,導致連線不上資料庫,業務無法正常進行
#預設連線數 mysql> show variables like '%max_connection%'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | max_connections | 151 | +-----------------+-------+ 1 row in set (0.00 sec)
解決問題思路:
1、首先先要考慮在我們 MySQL 資料庫引數檔案裡面,對應的 max_connections
這個引數值是不是設定的太小了,導致客戶端連線數超過了資料庫所承受的最大值。
-
該值預設大小是 151,可以根據實際情況進行調整。
-
對應解決辦法:
set global max_connections=500
所以這又反映出了,在新上線一個業務系統的時候,要做好壓力測試。保證後期對資料庫進行優化調整。
結果:
如果寫入大資料時,因為預設的配置太小,插入和更新操作會因為 max_allowed_packet 引數限制,而導致失敗。
當一個MySQL客戶或mysqld伺服器得到一個max_allowed_packet個位元組長的包, 它發出一個Packet too large錯誤並終止連線。
mysql> show variables like 'max_allowed_packet'; +--------------------+---------+ | Variable_name | Value | +--------------------+---------+ | max_allowed_packet | 4194304 | +--------------------+---------+
預設是4M大小
可以使用mysqld的命令列選項設定max_allowed_packet為一個更大的尺寸。 例如, 如果將一個全長的BLOB存入一張表中, 需要用max_allowed_packet=24M選項來啟動mysql。
Max_allowed_packet的取值範圍是1024B~1GB
當然不要亂設定,根據具體環境要求,設定太大業務
# 具體設定max_allowed_packet大小 mysql> set @@global.max_allowed_packet= #在my.cnf 加入這個 max_allowed_packet= 10M
如果是靜態引數還是要重啟服務才會生效,動態引數則不用
#預設連線數 mysql> show variables like '%max_connection%'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | max_connections | 151 | +-----------------+-------+ 1 row in set (0.00 sec) #修改連線數為500 mysql> set @@global.max_connections=500; Query OK, 0 rows affected (0.00 sec) #檢視是否修改成功 mysql> show variables like '%max_connection%'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | max_connections | 500 | +-----------------+-------+ # 在my.cnf 的[mysqld]下面加上 max_connections=500就可以了,也不用重啟服務
忘記了MySQL的root使用者的口令 在my.cnf中新增skip-grant-tables=1選項重啟mysqld
[root@mysql-150 ~]# mysql -u root -h 127.0.0.1 mysql> flush privileges; mysql> grant all privileges on *.* to root@'localhost' identified by '456789'; mysql> exit # 在my.cnf 將skip-grant-tables=1選項去掉 # 重啟mysqld之後就可以用最新的密碼登入 [root@mysql-150 ~]# vim /etc/my.cnf [root@mysql-150 ~]# service mysql restart Shutting down MySQL............ SUCCESS! Starting MySQL. SUCCESS! [root@mysql-150 ~]# mysql -u root -p456789 -h 127.0.0.1
# 建立一個使用者 mysql> create user keme@'localhost' identified by '123456'; # 給一個只讀許可權 mysql> grant select on *.* to keme@'localhost'; # 可以從本地登入 [root@mysql-150 ~]# mysql -u keme -p123456 # 把keme@'localhost' 給lock住,不讓其使用 mysql> alter user keme@'localhost' account lock; # 在看看能不能從本地登入 [root@mysql-150 ~]# mysql -u keme -p123456 mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 3118 (HY000): Access denied for user 'keme'@'localhost'. Account is locked. # 檢視該使用者是否鎖定 mysql> select host,user,account_locked from mysql.user where user='keme'; +-----------+------+----------------+ | host | user | account_locked | +-----------+------+----------------+ | localhost | keme | Y | +-----------+------+----------------+ Y已鎖定 # 然後解鎖該keme使用者 mysql> alter user keme@'localhost' account unlock; # 再去登入keme使用者 [root@mysql-150 ~]# mysql -u keme -p123456
臨時新增:
# 首先要確定mysql 的安裝位置 shell> export PATH=$PATH:/usr/local/mysql/bin
永久設定:
# 在/etc/profile 中末尾新增 PATH=$PATH:$HOME/bin:/usr/local/mysql/bin export PATH 儲存退出後執行: source /etc/bash_profile即可。
模式定義MySQL應支援哪些SQL語法, 以及應執行哪種資料驗證檢查。 這樣可以更容易地在不同的環境中使用MySQL, 並結合其它資料庫伺服器使用MySQL。
檢視當前的sql_mode
mysql> show variables like 'sql_mode'; +---------------+-------------------------------------------------------------------------------------------------------------------------------------------+ | Variable_name | Value | +---------------+-------------------------------------------------------------------------------------------------------------------------------------------+ | sql_mode | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | +---------------+-------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> select @@sql_mode; +-------------------------------------------------------------------------------------------------------------------------------------------+ | @@sql_mode | +-------------------------------------------------------------------------------------------------------------------------------------------+ | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | +-------------------------------------------------------------------------------------------------------------------------------------------+
- ANSI
更改語法和行為, 使其更符合標準SQL。
- STRICT_TRANS_TABLES
- TRADITIONAL
sql mode常用值
- ONLY_FULL_GROUP_BY
但這有個條件:如果查詢是主鍵列或是唯一索引且非空列,分組列根據主鍵列或者唯一索引且空(null)則sql 分組查詢有效
- NO_AUTO_VALUE_ON_ZERO
該值影響自增長列的插入。預設設定下,插入0或NULL代表生成下一個自增長值。如果使用者希望插入的值為0,而該列又是自增長的,那麼這個選項就有用了。
- STRICT_TRANS_TABLES
為事務儲存引擎啟用嚴格模式, 也可能為非事務儲存引擎啟用嚴格模式。
嚴格模式控制MySQL如何處理非法或丟失的輸入值。 有幾種原因可以使一個值為非法。 例如, 資料型別錯 誤, 不適合列, 或超出範圍。 當新插入的行不包含某列的沒有顯示定義DEFAULT子句的值,則該值被丟失。 對於事務表, 當啟用STRICT_ALL_TABLES或STRICT_TRANS_TABLES模式時, 如果語句中有非法或丟失值, 則會出現錯誤。 語句被放棄並回滾。
- NO_ZERO_IN_DATE
在嚴格模式下,不允許日期和月份為零
- NO_ZERO_DATE
設定該值,mysql資料庫不允許插入零日期,插入零日期會丟擲錯誤而不是警告。
- ERROR_FOR_DIVISION_BY_ZERO
在INSERT或UPDATE過程中,如果資料被零除,則產生錯誤而非警告。如果未給出該模式,那麼資料被零除時MySQL返回NULL
- NO_AUTO_CREATE_USER
禁止GRANT建立密碼為空的使用者
- NO_ENGINE_SUBSTITUTION
如果需要的儲存引擎被禁用或未編譯,那麼丟擲錯誤。不設定此值時,用預設的儲存引擎替代,並丟擲一個異常
- PIPES_AS_CONCAT
將”||”視為字串的連線操作符而非或運算子,這和Oracle資料庫是一樣的,也和字串的拼接函式Concat相類似
舉例:
# 建立一個測試表 CREATE TABLE `employee` ( `eid` int(11) NOT NULL, `ename` varchar(64) DEFAULT NULL, `sex` int(11) DEFAULT NULL, PRIMARY KEY (`eid`) ) ENGINE=InnoDB; # 插入幾條資料 insert into employee (eid,ename,sex) values (1,'keme',18),(2,'xixi',22),(3,'yj',18),(4,'kk',18),(5,'yy',18),(6,'xx',35); # 設定當前會話的sql_mode為如下 mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'; mysql> select eid,ename,count(*) from employee group by ename; +-----+-------+----------+ | eid | ename | count(*) | +-----+-------+----------+ | 1 | keme | 1 | | 4 | kk | 1 | | 2 | xixi | 1 | | 6 | xx | 1 | | 3 | yj | 1 | | 5 | yy | 1 | +-----+-------+----------+ # 重新設定當前的sql_mode 為如下 mysql> set @@sql_mode='ONLY_FULL_GROUP_BY'; mysql> select eid,ename,count(*) from employee group by ename; ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'beta.employee.eid' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by mysql> select eid,ename ,count(*) from employee group by eid; +-----+-------+----------+ | eid | ename | count(*) | +-----+-------+----------+ | 1 | keme | 1 | | 2 | xixi | 1 | | 3 | yj | 1 | | 4 | kk | 1 | | 5 | yy | 1 | | 6 | xx | 1 | +-----+-------+----------+ 6 rows in set (0.00 sec) mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'; mysql> insert into employee values(7,'ke','male'); ERROR 1366 (HY000): Incorrect integer value: 'male' for column 'sex' at row 1 mysql> set @@sql_mode='ANSI'; Query OK, 0 rows affected (0.00 sec) mysql> select @@sql_mode; +--------------------------------------------------------------------------------+ | @@sql_mode | +--------------------------------------------------------------------------------+ | REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI | +--------------------------------------------------------------------------------+ #改成ANSI模式就可以插入成功了,只不過識別成了0 mysql> insert into employee values(7,'ke','male'); Query OK, 1 row affected, 1 warning (0.01 sec) mysql> select * from employee where eid=7; +-----+-------+------+ | eid | ename | sex | +-----+-------+------+ | 7 | ke | 0 | +-----+-------+------+ 1 row in set (0.00 sec) mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> select @@sql_mode; +--------------------------------------------+ | @@sql_mode | +--------------------------------------------+ | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | +--------------------------------------------+ 1 row in set (0.00 sec) mysql> insert into employee values (8,'ww',17/0); Query OK, 1 row affected (0.00 sec) mysql> select * from employee where eid=8; +-----+-------+------+ | eid | ename | sex | +-----+-------+------+ | 8 | ww | NULL | +-----+-------+------+ mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,ERROR_FOR_DIVISION_BY_ZERO'; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> select @@sql_mode; +-----------------------------------------------------------------------+ | @@sql_mode | +-----------------------------------------------------------------------+ | STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION | +-----------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> insert into employee values (9,'ee',18/0); ERROR 1365 (22012): Division by 0 mysql> alter table employee modify ename varchar(5); mysql> set @@sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION'; mysql> insert into employee values (9,'qweradsf',11); ERROR 1406 (22001): Data too long for column 'ename' at row 1 mysql> set @@sql_mode='ANSI'; mysql> insert into employee values (9,'qweradsf',11); mysql> select * from employee where eid=9; +-----+-------+------+ | eid | ename | sex | +-----+-------+------+ | 9 | qwera | 11 | +-----+-------+------+ mysql> set @@sql_mode='TRADITIONAL'; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> select @@sql_mode; TRADITIONAL模式有如下值: |STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
MAX_UPDATES_PER_HOUR:一個使用者在一個小時內可以執行修改的次數(僅包含修 改資料庫或表的語句)
MAX_CONNECTIONS_PER_HOUR:允許使用者每小時連線的次數
MAX_USER_CONNECTIONS:一個使用者可以在同一時間連MySQL例項的數量
通過執行create user/alter user設定/修改使用者的資源限制
# 建立一個使用者並設定其資源限制 CREATE USER 'keme1'@'localhost' IDENTIFIED BY '123456' WITH MAX_QUERIES_PER_HOUR 20 MAX_UPDATES_PER_HOUR 10 MAX_CONNECTIONS_PER_HOUR 5 MAX_USER_CONNECTIONS 2; #keme1 這個使用者 一個小時可以查詢20次, 修改10次,一個小時可以連線5次,同一時刻只允許兩個使用者 #取消某項資源限制既是把原先的值修改成0 mysql> alter user 'keme1'@'localhost' WITH MAX_CONNECTIONS_PER_HOUR 0; # 當針對某個使用者的max_user_connections非0時, 則忽略全域性系統引數max_user_connections, 反之則全域性系統引數生效
在確保主從資料一致性的前提下,可以在從庫進行錯誤跳過。
像從庫如果不提供什麼服務的話可以在從庫中開啟 read_only 引數,禁止在從庫進行寫入操作,還有使用者必須沒有super 許可權,設定read_only才會生效。
這是正常的狀態
10.0.0.150 是主
10.0.0.151 是從
先模擬故障
# 這是本次的表結構 mysql> show create table students; | students | CREATE TABLE `students` ( `sid` int(11) NOT NULL, `sname` varchar(20) DEFAULT NULL, `sex` int(11) DEFAULT NULL, PRIMARY KEY (`sid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 #主庫執行,是個空表 mysql> select * from students; Empty set (0.00 sec) #在從庫 ,給students 加1條資料: mysql> insert into students values (1,'keme',0); mysql> show slave status\G; ... Slave_IO_Running: Yes Slave_SQL_Running: Yes ... 看主從狀態是正常的 # 從庫檢視students 資料 mysql> select * from students; +-----+-------+------+ | sid | sname | sex | +-----+-------+------+ | 1 | keme | 0 | +-----+-------+------+ # 在主庫檢視students 表 mysql> select * from students; Empty set (0.00 sec) # 插入相同主鍵的值 mysql> insert into students values (1,'keme',1); # 檢視students表 mysql> select * from students; +-----+-------+------+ | sid | sname | sex | +-----+-------+------+ | 1 | keme | 1 | +-----+-------+------+ # 檢視從庫狀態 mysql> show slave status\G; ... Slave_IO_Running: Yes Slave_SQL_Running: No Last_SQL_Error: Could not execute Write_rows event on table beta.students; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000023, end_log_pos 11789 ... # 主從狀態不一致了,造成的原因是主鍵衝突
解決辦法
# 停止從庫 mysql> stop slave; # 在從庫刪除主鍵衝突的那條語句, 把主庫執行的那條語句在從庫執行 mysql> delete from students where sid=1; mysql> insert into students values (1,'keme',1); # 同步跳過臨時錯誤 mysql> set global sql_slave_skip_counter = 1; mysql> start slave; mysql> show slave status\G; ... Slave_IO_Running: Yes Slave_SQL_Running: Yes ... # 主庫再次插入資料,看看從庫是不是能夠同步 mysql> insert into students values (2,'keme',1); # 從庫檢視 mysql> select * from students; +-----+-------+------+ | sid | sname | sex | +-----+-------+------+ | 1 | keme | 1 | | 2 | keme | 1 | +-----+-------+------+ 2 rows in set (0.00 sec) # OK,同步成功了, 一般主從錯誤也就解決了
首先主從問題不一致了,你的監控預警機制了,給你發簡訊或者釘釘,這時候你應該儘快去修復從庫,比如就像上面跳過臨時同步錯誤,暫時讓其恢復正常同步。
現在修改我的主從模式為GTID,這是我的測試環境隨便改,
enforce_gtid_consitency=on :使用GTID模式複製時,需要開啟此引數,用來保證GTID的一致性。
log-bin=on :Msql 做主從必須開啟binlog
log-slave-updates=1 :覺得slave 從master 接收到的更新且執行完之後,執行的binlog是否記錄到slave的binlog中,建議開啟
binlog_format=row :強烈建議binlog_format使用row格式 在mysql 5.7.6 版本以後預設就是row
skip-slave-start=1 :當slave 資料庫啟動的時候,slave 不會自動開啟複製
主庫操作,在[mysqld] 加一下引數,我這個做過主從, 只加一部分引數
# my.cnf 中內容 [mysqld] gtid-mode=on enforce-gtid-consistency=on log-slave-updates=1
從庫操作
# my.cnf 中內容 [mysqld] gtid-mode=on enforce-gtid-consistency=on log-slave-updates=1 skip-slave-start=1
重啟主從資料庫
在從庫 操作重新設定主從庫的複製關係
mysql> CHANGE MASTER TO MASTER_HOST = '10.0.0.150', MASTER_PORT = 3306, MASTER_USER = 'repl', MASTER_PASSWORD = '123456', MASTER_AUTO_POSITION = 1; mysql> start slave; #檢視主從狀態 mysql> show slave status\G; ... Slave_IO_Running: Yes Slave_SQL_Running: Yes ...
如果是在GTID模式下出現複製報錯, 則使用SQL_SLAVE_SKIP_COUNTER語句會報錯
在GTID 模式的複製情況下,如果slave 發生錯誤,則可以通過跳過該事務的方式恢復主從複製。
現在人為製造slave錯誤
# 在從庫的sutdents 表插入一條資料 mysql> select * from students; +-----+-------+------+ | sid | sname | sex | +-----+-------+------+ | 1 | keme | 1 | | 2 | keme | 1 | +-----+-------+------+ mysql> insert into students values (3,'keme',0); # 在檢視從庫的資料 mysql> select * from students; +-----+-------+------+ | sid | sname | sex | +-----+-------+------+ | 1 | keme | 1 | | 2 | keme | 1 | | 3 | keme | 0 | +-----+-------+------+ # 主庫也插入主鍵為3這條資料,引發主從同步錯誤 mysql> insert into students values (3,'keme',1);
主從報錯了:
開始位置(Exec_Master_Log_Pos)是154 ,結束位置是(end_log_pos ) 395,可以去主庫分析下binlog ,看一下發生衝突的事務是哪個。
可以看到接收並且執行了GTID事件 是
從庫執行了這些 5a13910d-1496-11e9-8375-000c29f859ce:1-3, f6c31435-38dd-11e9-ac93-000c299bcbee:1-53096 收到卻沒執行的事務號: Retrieved_Gtid_Set: f6c31435-38dd-11e9-ac93-000c299bcbee:53097
mysql> select * from students where sid=3; +-----+-------+------+ | sid | sname | sex | +-----+-------+------+ | 3 | keme | 0 | +-----+-------+------+
基於GTID模式的複製,跳過一個事務,需要利用一個空事務來完成。
mysql> stop slave; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> set GTID_NEXT='f6c31435-38dd-11e9-ac93-000c299bcbee:53097'; Query OK, 0 rows affected (0.00 sec) mysql> begin;commit; Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> set GTID_NEXT='AUTOMATIC'; Query OK, 0 rows affected (0.00 sec) mysql> start slave; Query OK, 0 rows affected (0.00 sec)
檢視slave 狀態
哪主從庫資料是否一致,就看3那條
# 主庫資料 mysql> select * from students where sid=3; +-----+-------+------+ | sid | sname | sex | +-----+-------+------+ | 3 | keme | 1 | +-----+-------+------+ #從庫資料 mysql> select * from students where sid=3; +-----+-------+------+ | sid | sname | sex | +-----+-------+------+ | 3 | keme | 0 | +-----+-------+------+
1 手動修改或者插入
2 用pt用具 來修復或者檢查不一致資料
由於我這是我的本地環境,我只手動修改資料,再看主從狀態
mysql> update students set sex=1 where sid=3; Query OK, 1 row affected (0.03 sec) Rows matched: 1 Changed: 1 Warnings: 0
注:不止是要主從解決錯誤,還要主從資料的一致性
如何修改了系統編碼了:
# centos 6.x 版本是/etc/sysconfig/i18n 修改這個檔案 shell> vim /etc/sysconfig/i18n # 這一行改為utf8 LANG=en_US.UTF-8 # 修改完,不要重啟,立即生效如下 shell> source /etc/sysconfig/i18n # centos 7.x 版本是/etc/locale.conf 這個檔案 [root@mysql-150 ~]# vim /etc/locale.conf LANG="en_US.UTF-8" #立即生效 [root@mysql-150 ~]# source /etc/locale.conf
- 資料庫層面:
在引數檔案中的[mysqld] 下,加入相應utf8字符集
# 注意資料庫的系統版本 5.6.x 和 5.7.x設定字符集引數不一樣,8.x和5.7.x設定是一樣的 #檢視當前資料庫的字符集引數,檢視當前字符集引數 mysql> show variables like '%character%'; # 檢視資料庫支援的字元編碼,和編碼的排序規則 mysql> show character set; # 修改sutdents表中sname 欄位的字元編碼 mysql> alter table students modify sname varchar(66) character set gbk; Query OK, 3 rows affected (0.06 sec) Records: 3 Duplicates: 0 Warnings: 0 #看看錶結構 mysql> show create table students; ... | students | CREATE TABLE `students` ( `sid` int(11) NOT NULL, `sname` varchar(66) CHARACTER SET gbk DEFAULT NULL, `sex` int(11) DEFAULT NULL, PRIMARY KEY (`sid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | ... # 檢視連線級字符集和排序規則 mysql> show variables like '%collation%'; +----------------------+-----------------+ | Variable_name | Value | +----------------------+-----------------+ | collation_connection | utf8_general_ci | | collation_database | utf8_general_ci | | collation_server | utf8_general_ci | +----------------------+-----------------+
從上面示例可以得出:
-
列級別字符集
-
表級別字符集
-
庫級別字符集
-
mysql 例項字符集
vim /etc/my.cnf [mysqld] init-connect='SET NAMES utf8' character-set-server=utf8 然後去資料庫操作: mysql> set @@global.character_set_server=utf8; Query OK, 0 rows affected (0.00 sec) mysql> set @@global.init_connect='SET NAMES utf8'; Query OK, 0 rows affected (0.00 sec) # 注 使用者操作的時候看看有沒有super許可權,對super使用者許可權 set names 不生效
有人說,修改完還是亂碼, 這時候就亂碼是哪個庫的字符集,哪個表的字符集,哪個欄位的字符集,還有作業系統字符集,程式連線的字符集,這些都的檢視。
比如:
# 舉例init_connect mysql> SET @@GLOBAL.init_connect='SET AUTOCOMMIT=0;set names utf8'; shell> vim my.cnf [mysqld] init_connect='SET AUTOCOMMIT=0;set names utf8'
-
每個資料庫客戶端連線都有自己的字符集和排序規則屬性,
客戶端傳送的語句的字符集是由character_set_client決定,
而與服務端互動時會根據character_set_connection和collation_connection兩個引數將接收到的語句轉化。當涉及到顯示字串的比較時,由collation_connection引數決定,
-
character_set_result引數決定了語句的執行結果以什麼字符集返回給客戶端
-
客戶端可以很方便的調整字符集和排序規則,比如使用SET NAMES 'charset_name' [COLLATE 'collation_name']表明後續的語句都以該字符集格式傳送給服務端,而執行結果也以此字符集格式返回。
set names 字符集
set names charset_name 語句相當於執行了以下三行語句: SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = charset_name;
SET character_set_client = charset_name; SET character_set_results = charset_name; SET character_set_connection = @@character_set_database;
資料庫從: 全域性資料庫server字符集——>資料庫字符集——> 表字符集——> 列字符集
shell> vim my.cnf [mysqld] init-connect='SET NAMES utf8mb4' character-set-server=utf8mb4 #登入資料庫執行以下語句 mysql> set @@global.character_set_server=utf8mb4; mysql> set @@global.init_connect='SET NAMES utf8mb4';
解決思路:
首先我們要先檢視資料庫的 error log。然後判斷是表損壞,還是許可權問題。還有可能磁碟空間不足導致的不能正常訪問表,作業系統的限制也要關注下,相關應用限制也要關注下;
#ulimit -n 檢視系統的最大開啟檔案數 [root@mysql-150 ~]# ulimit -n 65535
檢視資料庫的開啟檔案數
mysql> show variables like 'open_files_limit'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | open_files_limit | 5000 | +------------------+-------+ # 根據業務實際情況修改開啟檔案數一般足夠用了,低版本的開啟檔案數,可能有點小, 注意一下
哪就是其他的問題了,可能是表的許可權,也可能是表出問題,根據錯誤日誌,具體分析
處理方法
-
repair table tablename
-
chown mysql.mysql 許可權 目錄
-
清理磁碟中的垃圾資料
-
-
mysql 引數的問題,是不是引數配置的不合理,一直不釋放連線;
-
mysql 語句的問題,資料庫查詢不夠優化,過度耗時。
-
大併發情況問題,導致 sleep 情況過多;
很多人都是重啟大法,重啟大法確實好, 能夠釋放,生產重啟對業務有影響的,不能隨便重啟的
shell指令碼+cron計劃任務,來kill sleep 執行緒,這個不靠譜啊, 你不知道 sleep 執行緒,裡面是不是還有事務還在執行沒有提交,也是sleep 狀態,這個kill 操作有點莽夫,對生產資料資料庫還是要理智啊。
我臨時解決的辦法:
-
-
修改 mysql 引數問題 ,修改
wait_timeout
和interactive_timeout
預設都是28800秒有,也就是8個小時以後才釋放空連結。
例子:
不同使用者登入到資料庫,wait_timeout和interactive_timeout
都是28800秒
修改引數,我生產環境設定的是半個小時,也就是1800秒
mysql> set global wait_timeout=1800; mysql> set global interactive_timeout=1800; shell> vim my.cnf [mysqld] wait_timeout=1800 interactive_timeout=1800
#開啟兩個會話視窗 mysql> # 重新登入了會話,wait_timeout和interactive會生效 mysql> show variables like 'wait_timeout'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | wait_timeout | 1800 | +---------------+-------+ 1 row in set (0.00 sec) mysql> show variables like 'interactive_timeout'; +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 1800 | +---------------------+-------+ 1 row in set (0.00 sec) #session2 mysql> #這個是其他使用者連線的mysql,這個會話一直沒有斷開,引數還是28800 mysql> show variables like 'wait_timeout'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | wait_timeout | 28800 | +---------------+-------+ 1 row in set (0.01 sec) mysql> show variables like 'interactive_timeout'; +---------------------+-------+ | Variable_name | Value | +---------------------+-------+ | interactive_timeout | 28800 | +---------------------+-------+ 1 row in set (0.00 sec)
這時候就要知道 造成 sleep 執行緒過多的原因來解決:
-
程式執行完畢,應該顯式呼叫mysql_close
-
-
能逐步分析系統的SQL查詢,找到查詢過慢的SQL優化
-
合理設定mysql引數值