導致結果:
連接數過多,導致連接不上數據庫,業務無法正常進行
#默認連接數 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
注:不止是要主從解決錯誤,還要主從數據的一致性
如果是生產的核心庫主從不一致,一定要查明原因,不然老是 dba 或者運維 背鍋
還有如果主從不一致性實在是太多太多不一致了,就重做數據庫吧
如果檢查的數據某幾張表不一致的情況下,可以把這幾張道出來,恢復到從庫
如何修改了系統編碼了:
# 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字符集——>數據庫字符集——> 表字符集——> 列字符集
解決思路:
首先我們要先查看數據庫的 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參數值