MySQL 的安裝方式有多種,可是對於不一樣場景,會有最適合該場景的 MySQL 安裝方式,下面就介紹一下 MySQL 常見的安裝方法,包括 rpm 安裝,yum 安裝,通用二進制安裝以及源碼編譯安裝,以 CentOS6.9 操做系統爲例。html
安裝速度較快,一般適用於企業中大規模部署 mysql,安裝步驟以下:node
(1)首先下載 MySQL 的 rpm 安裝包, 以下:mysql
客戶端:http://dev.mysql.com/get/Down…linux
服務端:http://dev.mysql.com/get/Down…c++
(2)下載完成以後,上傳至服務器的指定軟件目錄下,好比:/home/software;面試
(3)首先查看主機上是否已經安裝過 mysql,使用以下命令查看:正則表達式
[root@WB-BLOG ~]# rpm -qa | grep -i mysql*
(4)若是存在,須要先卸載原有 mysql,使用以下命令:算法
[root@WB-BLOG ~]# rpm -e --nodeps mysql-libs
注:–nodeps 表示無依賴卸載 mysql-libs,防止卸載依賴的庫而致使後續安裝出錯sql
(5)添加 mysql 用戶:shell
[root@WB-BLOG software]# useradd mysql -s /sbin/nologin -M
(6)卸載完成以後,開始安裝,首先安裝服務端,而後再安裝客戶端:
服務端安裝:
[root@WB-BLOG ~]# rpm -ivh MySQL-server-5.6.32-1.linux_glibc2.5.x86_64.rpm
注:上述命令執行完畢以後,會自動初始化數據庫,數據目錄默認在 /var/lib/mysql 下,查看控制檯實時日誌中是否有 ERROR 信息,若是無 ERROR 信息,表示服務端安裝完成,Warning 信息能夠忽略。安裝完成以後,會在 /root/.mysql_secret 文件中生成 mysql 的默認密碼,能夠經過 cat 命令查看便可:cat /root/.mysql_secret
客戶端安裝:
[root@WB-BLOG ~]# rpm -ivh MySQL-client-5.6.32-1.linux_glibc2.5.x86_64.rpm
注:安裝客戶端的目的是能夠再服務器上使用到 mysql 的一些客戶端鏈接命令,好比:mysql 命令,若是肯定不在服務器上操做 mysql,能夠不安裝此客戶端。
(7)安裝完成以後,添加 mysql 的配置文件 my.cnf,對於 mysql,改配置文件有一個加載順序,mysql 啓動的時候會按照這個順序去加載,順序爲:/etc/my.cnf,basedir/my.cnf,datadir/my.cnf,~/.my.cnf
編輯 /etc/my.cnf 配置文件,寫入以下內容:
[mysql] socket = /tmp/mysql.sock [mysqld] port = 3306 socket = /tmp/mysql.sock character-set-server = UTF8 innodb_file_per_table = 1 innodb_flush_log_at_trx_commit = 2
(8)編輯完配置文件以後,保存。而後啓動 mysql 數據庫,以下:
[root@WB-BLOG ~]# service mysql start
(9)啓動以後,使用以下 mysql 命令行工具登錄 mysql,默認密碼爲 /root/.mysql_secret 中生成的,登錄 mysql 以後,完成以下的初始工做:
[root@WB-BLOG mysql]# mysql -uroot -pBcbwbAXM_kUL8lpE -h127.0.0.1 -P3306
a. 修改 root 密碼,有兩種方法:
方法一:在 shell 命令行中使用」mysqladmin」命令修改
[root@WB-BLOG mysql]# mysqladmin -uroot -pBcbwbAXM_kUL8lpE password 'root'
注:修改密碼的時候須要使用 password 函數,並且密碼儘量設置複雜一些;
b. 修改遠程鏈接權限:
mysql> select user,host,password from mysql.user; #查看當前已有用戶及權限 mysql> update user set host = '192.168.0.%' where host = 'wb-blog';
注:」set host = ‘192.168.0.%’」表示只容許 192.168.0 網段內的主機使用’root’用戶遠程鏈接,此處也能夠指定 ip 段或者對全部用戶開放,可根據實際場景配置
mysql> flush privileges; #刷新權限,讓 mysql 重讀權限表
c. 刪除多餘及不安全的用戶:
mysql> drop user 'root'@'::1'; #該用戶爲 ipv6 的用戶,暫時沒用,能夠刪掉
d. 刪除無用的數據庫:
mysql> drop database test; #該數據庫在初始化的時候是默認添加的,無用,可刪除
至此,rpm 方式的 MySQL 安裝及初始化完畢。
通用二進制安裝的優勢就是能夠同時在一臺主機上安裝多個不一樣版本的 mysql,並且在安裝完成以後包括了一些經常使用的庫文件,安裝步驟以下:
(1)首先下載通用二進制安裝包,下載地址爲:https://dev.mysql.com/get/Dow…
(2)使用 yum 命令安裝 mysql 的依賴庫,mysql 主要有以下兩個依賴庫:
[root@WB-BLOG mysql]# yum install -y ncurses-devel libaio-devel
注:若是沒有網絡的狀況下,使用 yum 安裝會提示錯誤。此時能夠下載依賴庫所對應的 rpm 包上傳至服務器完成安裝;或者還能夠使用 iso 鏡像文件搭建私有的 yum 源,後面寫文章介紹如何在局域網或者本地搭建及配置私有得的 yum 源。
(3)安裝完成以後,添加 mysql 用戶:
[root@WB-BLOG ~]# useradd mysql -s /sbin/nologin -M
(4)解壓 mysql 通用二進制安裝包,並重命名目錄:
[root@WB-BLOG home]# tar xf mysql-5.6.40-linux-glibc2.12-x86_64.tar.gz -C /usr/local/ [root@WB-BLOG home]# cd /usr/local/ [root@WB-BLOG local]# mv mysql-5.6.40-linux-glibc2.12-x86_64.tar.gz/ mysql-5.6.40
(5)建立 mysql 的數據目錄,並受權 mysql 用戶。注意,數據目錄最好別放在系統盤上,若是數據量後期比較大的話,最好事先選擇一個空間比較大的數據盤做爲 mysql 的存儲目錄,方便後期數據備份及遷移
[root@WB-BLOG local]# mkdir -pv /mysql_data/ [root@WB-BLOG local]# chown -R mysql.mysql /mysql_data
(6)編輯 mysql 的配置文件 my.cnf,能夠從 mysql 解壓目錄中拷貝一份到 /etc/my.cnf 下,並修改,在配置文件中指定 mysql 的一些配置參數,以下:
[mysql] socket = /mysql_data/mysql.sock [mysqld] basedir = /usr/local/mysql-5.6.40 datadir = /mysql_data/ character-set-server = UTF8 port = 3306 server_id = 3 #後期作 mysql 主從使用,可暫不配置 socket = /mysql_data/mysql.sock innodb_file_per_table = 1 innodb_flush_log_at_trx_commit = 2
(7)初始化 mysql 數據庫:
[root@WB-BLOG local]# cd /usr/local/mysql-5.6.39/ [root@WB-BLOG mysql-5.6.39]# ./scripts/mysql_install_db --basedir=/usr/local/mysql-5.6.39 --datadir=/mysql_data --user=mysql
注意:看到有以下所示的兩個單行的 OK 字樣,表示初始化成功.
Installing MySQL system tables... OK Filling help tables... OK
(8)拷貝 mysql 的啓動腳本文件至 /etc/init.d/ 目錄下,並重命名爲 mysqld,授予其可執行權限:
[root@WB-BLOG mysql-5.6.39]# cp /usr/local/mysql-5.6.40/support-files/mysql.server /etc/init.d/mysqld [root@WB-BLOG mysql-5.6.39]# chmod +x /etc/init.d/mysqld
(9)修改 mysql 啓動腳本中的默認安裝路徑:
[root@WB-BLOG mysql-5.6.39]# sed -i "s#/usr/local/mysql#/usr/local/mysql-5.6.40#g" /etc/init.d/mysqld
(10)將 mysqld 添加至系統服務,並設置自動啓動:
[root@WB-BLOG mysql-5.6.39]# chkconfig --level 2345 mysqld on #配置 [root@WB-BLOG mysql-5.6.39]# chkconfig --list mysqld #查看
(11)使用跳過受權表方式啓動 mysql 數據庫,並登錄 mysql,設置密碼,而後完成 mysql 使用前的初始化準備工做:
[root@WB-BLOG mysql-5.6.39]# /usr/local/mysql-5.6.39/bin/mysqld_safe --defaults-file=/etc/my.cnf --skip-grant-tables & [root@WB-BLOG mysql-5.6.39]# mysql -uroot -p #而後兩次回車 mysql> update mysql.user set password = password('root') where user = 'root'; #修改密碼: mysql> delete from mysql.user where host = '::1'; #刪除多餘用戶 mysql> flush privileges; #重讀權限表 mysql> drop database test; #清理多餘數據庫
(12)退出 mysql 命令行,使用 mysqladmin 命令關閉數據庫,並從新啓動,使數據庫再次使用權限認證:
mysql> q [root@WB-BLOG mysql-5.6.39]# ./bin/mysqladmin -uroot -proot shutdown #須要使用剛纔修改的密碼 [root@WB-BLOG mysql-5.6.39]# service mysqld start
(13)配置 mysql 的環境變量,方便使用客戶端鏈接:
[root@WB-BLOG mysql-5.6.39]# vim /etc/profile 添加以下內容: MYSQL_HOME=/usr/local/mysql-5.6.39 PATH=$PATH:$JAVA_HOME/bin:$MYSQL_HOME/bin [root@WB-BLOG mysql-5.6.39]# source /etc/profile# 使配置文件生效
至此,通用二進制方式的 mysql 安裝及初始化完畢。
該方式安裝過程比較慢,機器性能很差的狀況下,大約須要 30 分鐘左右,一般適用於 mysql 定製化的安裝,好比須要加入一些第三方的插件及依賴庫等,安裝方法以下:
(1)源碼安裝須要使用到 cmake,首先下載 cmake 和 mysql 的源碼,上傳至服務器:
cmake 下載地址:https://cmake.org/files/v2.8/…
mysql 源碼下載地址:https://dev.mysql.com/get/Dow…
(2)使用 yum 方式安裝 gcc 和 gcc-c++,不然編譯 cmake 和 mysql 的時候會報錯,以下:
[root@WB-BLOG mysql-5.6.39]# yum install -y gcc gcc-c++
(3)解壓 cmake,並進入 cmake 軟件目錄:
[root@WB-BLOG software]# tar xf cmake-2.8.8.tar.gz [root@WB-BLOG software]# cd cmake-2.8.8 [root@WB-BLOG cmake-2.8.8]# ./configure [root@WB-BLOG cmake-2.8.8]# gmake [root@WB-BLOG cmake-2.8.8]# gmake install
(4)安裝 mysql 的依賴庫:ncurses-devel
[root@WB-BLOG software]# yum install -y ncurses-devel
(5)解壓 mysql:
[root@WB-BLOG software]# tar xf mysql-5.6.35.tar.gz && cd mysql-5.6.35 [root@WB-BLOG software]# mv mysql-5.6.35 /usr/local
(6)建立 mysql 組和 mysql 用戶:
[root@WB-BLOG mysql-5.6.35]# groupadd mysql [root@WB-BLOG mysql-5.6.35]# useradd mysql -s /sbin/nologin -M -g mysql
(7)建立 mysql 的數據目錄並受權:
[root@WB-BLOG mysql-5.6.35]# mkdir -pv /mysql_data/ [root@WB-BLOG mysql-5.6.35]# chown -R mysql.mysql /mysql_data/
(8)使用 cmake 編譯 mysql,以下的編譯選項爲最基本的,更多選項能夠參考官方文檔:
[root@WB-BLOG mysql-5.6.35]# cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql-5.6.35 -DMYSQL_DATADIR=/mysql_data/ -DMYSQL_UNIX_ADDR=/mysql_data/mysql.sock -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DEXTRA_CHARSETS=gbk,gb2312,utf8,ascii -DENABLED_LOCAL_INFILE=ON -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_FEDERATED_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITHOUT_EXAMPLE_STORAGE_ENGINE=1 -DWITHOUT_PARTITION_STORAGE_ENGINE=0 -DWITH_FAST_MUTEXES=1 -DWITH_ZLIB=bundled -DENABLED_LOCAL_INFILE=1 -DWITH_READLINE=1 -DWITH_EMBEDDED_SERVER=1 -DWITH_DEBUG=0 -DWITH_PARTITION_STORAGE_ENGINE=1
…等待編譯…
[root@WB-BLOG mysql-5.6.35]# make [root@WB-BLOG mysql-5.6.35]# make install
(9)若是上述過程正常結束,表示 mysql 編譯安裝成功,不然停下來檢查編譯過程當中的錯誤,一般編譯期的錯誤多數爲缺乏類庫致使,可安裝相關類庫後從新編譯。而後編輯 mysql 的配置文件 my.cnf,寫入以下內容:
[mysql] socket = /mysql_data/mysql.sock [mysqld] character-set-server = UTF8 basedir = /usr/local/mysql-5.6.35 datadir = /mysql_data port = 3306 server_id = 3 socket = /mysql_data/mysql.sock innodb_file_per_table = 1 skip-name-resolve innodb_flush_log_at_trx_commit = 2
(10)初始化 mysql 數據庫:
[root@WB-BLOG mysql-5.6.35]# cd /usr/local/mysql-5.6.35/ [root@WB-BLOG mysql-5.6.35]# ./scripts/mysql_install_db --basedir=/usr/local/mysql-5.6.35 --datadir=/mysql_data/ --user=mysql
(11)看到以下的字樣,表示 mysql 數據庫初始化成功:
Installing MySQL system tables... OK Filling help tables... OK
(12)拷貝啓動腳本到 /etc/init.d 目錄下:
[root@WB-BLOG mysql-5.6.35]# cp /usr/local/mysql-5.6.35/support-files/mysql.server.sh /etc/init.d/mysqld [root@WB-BLOG mysql-5.6.35]# vim /etc/init.d/mysqld #編輯腳本,修改 basedir 和 datadir 目錄爲安裝的目錄
找到 basedir 和 datadir,而後修改成以下內容,並保存退出:
basedir=/usr/local/mysql-5.6.35 datadir=/mysql_data/
(13)受權腳本的執行權限,使用跳過受權表的方式啓動,而後修改密碼,刪除多餘的用戶和數據庫,並配置環境變量,具體步驟同「通用二進制安裝中的(11),(12),(13)」,此處後續步驟略。
[root@WB-BLOG mysql-5.6.35]# chmod +x /etc/init.d/mysqld ...
至此,源碼編譯安裝 mysql 介紹完畢。
MySQL 數據庫環境搭建好以後,就一塊開始 MySQL 的學習之旅吧?本次主要介紹 MySQL 的基本操做之」建庫,建表,刪庫,刪表」。
一、建庫以前,首先須要鏈接到 MySQL 數據庫,常見的鏈接工具工具爲:」mysql」客戶端命令,基本用法以下:
[root@WB-BLOG ~]# mysql <options>
options 中經常使用的選項有:
-u: 指定鏈接數據庫實例所使用的用戶名
-p: 指定鏈接數據庫實例所使用的密碼
-h: 指定須要鏈接的目標數據實例所在主機的 ip 地址或者域名,若是是服務器本地鏈接,可省略
-P: 指定須要鏈接的目標數據庫實例所監聽的 tcp 端口,注意是大寫的 P。若是使用的是默認端口,此選項可省略
…該命令還有其餘不少不太經常使用的選項,能夠自行使用」mysql –help」命令查看,此處略。
示例:使用用戶名爲 root 密碼爲 root 的用戶鏈接 192.168.0.10 服務器上端口爲 3306 的數據庫實例:
[root@WB-BLOG ~]# mysql -uroot -proot -h127.0.0.1 -P3306
注:除了 -p 指定的密碼的選項以外,其他的參數和對應的值之間能夠不加空格,也可加空格,可是 -p 參數和密碼之間不可有空格,不然會被認爲另一個參數,須要從新輸入密碼。
二、進入 mysql 命令行以後,就能夠建立數據庫了,首先查看當前已經存在的數據庫,使用 show 命令,show 命令的使用選項以下:
mysql> show <options>
options 常見的選項以下:
tables: 查看當前庫下的全部表
databases: 查看當前實例下的全部數據庫,不必定是全部庫,和登錄用戶的權限有關
create database db_name:show 後接 create database 命令,表示查看名稱爲 db_name 的數據庫的建立過程
create database table_name:show 後接 create table 命令,表示查看名稱爲 table_name 的表的建立過程
warnings: 查看 sql 執行的警告信息
events: 查看當前數據庫所對應的事件信息
binary logs | master logs: 查看當前數據庫實例對應的二進制日誌文件信息(bin_log_pos 和 bin_log_file)
status: 查看當前數據庫實例的運行狀態信息
index|indexes from table_name: 查看指定表中的索引信息
…其餘不經常使用選項此處暫時略,後續再介紹。
示例:查看當前登陸用戶有權查看的全部數據庫:
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.00 sec)
因爲使用的是 root 用戶登陸,故能夠看到全部數據庫;若是用某個普通用戶登陸,只能看到該用戶有權查看的全部庫,具體權限管理後期介紹。
三、建立數據庫,使用 create 命令,create 命令用法以下:
mysql> create <options>
options 常見選項以下:
database db_name [option]: 後接 database 關鍵字表示建立名稱爲 db_name 的數據庫,option 選項中能夠指定字符集
table table_name [option]: 後接 table 關鍵字表示建立名稱爲 table_name 的表,option 選項中能夠指定字符集
index index_name on table_name(field): 後接 index 關鍵字表示在 table_name 表的 field 字段上建立名稱爲 index_name 的索引
procedure pro_name [option]: 後接 procedure 關鍵字表示在當前庫的某個表上建立一個存儲過程,option 選項表示具體的建立過程
…其餘選項此處暫不介紹,後續再介紹。
示例:建立一個名稱爲 db_shop 的數據庫,使用 UTF8 字符集,以下:
mysql> create database db_shop character set UTF8; Query OK, 1 row affected (0.21 sec) mysql> show databases; #查看建立的數據庫 +--------------------+ | Database | +--------------------+ | information_schema | | db_shop| | mysql | | performance_schema | | test | +--------------------+ 5 rows in set (0.00 sec) mysql> show create database db_shop; #查看 db_shop 數據庫的建立過程 +----------+------------------------------------------------------------------+ | Database | Create Database | +----------+------------------------------------------------------------------+ | db_shop | CREATE DATABASE `db_shop` /*!40100 DEFAULT CHARACTER SET utf8 */ | +----------+------------------------------------------------------------------+ 1 row in set (0.00 sec)
4. 建立表,在建表以前首先須要先選擇數據庫,使用 use 命令,用法以下:
mysql> use <db_name>
示例:在 db_shop 庫中建立一個名稱爲 t_goods 的表,使用 UTF8 字符集,表中字段包括 id(bigint),goods_name(varchar(50)),goods_price(bigint)[金錢類能夠使用字符串或者分來存儲,此處使用分來存儲],create_time(datetime),建立過程以下:
mysql> use db_shop; #選庫 mysql> create table t_goods(id bigint primary key auto_increment,goods_name varchar(50) not null default '',goods_price bigint,create_time datetime) default character set UTF8; #建表 Query OK, 0 rows affected (0.76 sec) mysql> show tables; #查看錶 +-------------------+ | Tables_in_db_shop | +-------------------+ | t_goods | +-------------------+ 1 row in set (0.00 sec) mysql> show create table t_goods G #查看建立庫的過程,G 表示按行展現 *************************** 1. row *************************** Table: t_goods Create Table: CREATE TABLE `t_goods` (`id` bigint(20) NOT NULL AUTO_INCREMENT, `goods_name` varchar(50) NOT NULL DEFAULT '', `goods_price` bigint(20) DEFAULT NULL, `create_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
注:MySQL 經常使用數據類型以下,詳細介紹請查看官方手冊,後期 sql 優化會重點對比講解每種類型的優缺點:
數值型整型:tinyint,smallint,mediumint,int,bigint
浮點數類型:double,float,decimal
字符串類型:char,varchar,varbinary
長文本類型:text
二進制類型:binary,blob
日期類型:timestamp,datetime,time,date,year
枚舉類型:enum
集合類型:set
五、刪除表,使用」drop table」命令,用法以下:
mysql> drop table <table_name>
示例:刪除名稱爲 t_goods 的表:
mysql> drop table t_goods; #刪除名稱爲 t_goods 的表 Query OK, 0 rows affected (0.16 sec) mysql> show tables; #查看當前庫下的全部表 Empty set (0.00 sec)
六、刪除數據庫,使用」drop database」命令,用法以下:
mysql> drop database <db_name>;
示例:刪除名稱爲 db_shop 的數據庫:
mysql> drop database db_shop; Query OK, 0 rows affected (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.01 sec)
七、退出 MySQL 的方法:
(1)方法 1:Ctrl+C
(2)方法 2:」quit」命令
(3)方法 3:q
至此,數據庫的基本操做之建庫,建表,刪庫,刪表操做介紹完畢,下一篇將介紹 MySQL 數據庫的常見操做,包括 DDL(數據定義語言),DCL(數據控制語言),DML(數據操縱語言),DQL(數據查詢語言)。
MySQL 基本操做之 DDL(數據定義語言),DML(數據操縱語言),DQL(數據查詢語言),DCL(數據控制語言)
做用:數據定義語言主要用來定義數據庫中的各種對象,包括用戶、庫、表、視圖、索引、觸發器、事件、存儲過程和函數等。
常見的 DDL 操做的基本用法以下:
CREATE USER #建立用戶
CREATE DATABASE #建立數據庫
CREATE TABLE #建立表
CREATE VIEW #建立視圖
CREATE INDEX #建立索引
CREATE TRIGGER #建立觸發器
CREATE EVENT #建立事件
CREATE PROCEDURE #建立存儲過程
CREATE FUNCTION #建立自定義函數
…其餘不經常使用的 DDL(如:TABLESPACE)操做可自行查閱資料…
一、建立用戶:
詳細用法:CREATE USER ‘username‘@’[ip/domain/netmask]’
參數解釋:
username: 表示登錄 MySQL 實例的用戶名 [ip/domain/ip range]: 表示數據庫實例容許的登錄 ip,域名或者 ip 段
示例:建立一個名稱爲 bingwang,登錄 ip 爲 192.168.0.10 的用戶:
mysql> CREATE USER 'bingwang'@'192.168.0.10';
二、建立數據庫,示例以下:
詳細用法:
CREATE DATABASE db_name;
示例以下:
# 建立一個名稱爲 test_db,字符集爲 utf8 的數據庫 mysql> CREATE DATABASE test_db DEFAULT CHARSET UTF8;
三、建立表:
詳細用法:CREATE TABLE table_name;
示例以下:
# 建立一個名稱爲 t_test,字符集爲 utf8,存儲引擎爲 InnoDB,字符校驗集爲 utf8_general_ci 的表: mysql> CREATE TABLE t_test ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50), PRIMARY KEY(id) ) ENGINE = InnoDB DEFAUL CHARSET = UTF8 COLLATE = utf8_general_ci;
四、建立視圖:
詳細用法:
CREATE VIEW view_name as <SELECT phrase>; 參數解釋: <SELECT phrase>: 查詢語句
示例以下:
# 建立一個視圖 t_view,用來查詢 t_test 中的 ID 爲 1 或者 2 的數據: mysql> CREATE VIEW test_view AS SELECT * FROM t_test WHERE id IN (1,2); #查看建立視圖的過程: mysql> SHOW CREATE VIEW test_view;
五、建立索引,有兩種方法,CREATE 和 ALTER,下面先介紹一下 CREATE:
詳細用法:
CREATE [UNIQUE] INDEX index_name ON table_name(field[num]) <OPTIONS>;
參數解釋:
UNIQUE: 表示建立的索引類型爲惟一索引,若是建立的爲通常索引能夠忽略該選項 table_name: 表名稱 field: 表中的某個字段。num 爲可選參數,若是 field 爲字符創類型,表示給該字段的前 num 個字符建立索引 OPTIONS: 表示可選選項,能夠指定索引使用的算法,好比:USING BTREE。不指定默認爲 BTREE;
示例以下:
(1)給 t_test 表中的 name 字段添加一個惟一索引,使用 BTREE 做爲其索引算法:
mysql> CREATE UNIQUE INDEX name_ind ON t_test(name) USING BTREE; mysql> SHOW [INDEX/INDEXES] FROM t_test; #查看 t_test 表中的索引,[INDEX/INDEXES]兩個關鍵字均可以
(2)給 t_test 表中的 name 字段的前 5 個字符建立通常索引,使用 BTREE 做爲其索引算法:
mysql> CREATE INDEX name_index ON t_test(name(5));
關於索引的更多用法及優化在後面的文章中會詳細講解。
六、建立觸發器:
詳細用法:
CREATE TRIGGER trigger_name trigger_time trigger_event FOR EACH ROW BEGIN trigger_stmt END;
示例:建立觸發器內容稍多,此處先稍微提一下,後面專門章節介紹;
七、建立存儲過程:
詳細用法:
CREATE PROCEDURE procedure_name([proc_parameter[,...]]) BEGIN ... 存儲過程體 END
示例:建立存儲過程內容稍多,此處先稍微提一下,後面專門章節介紹;
八、建立自定義函數:
詳細用法:
CREATE FUNCTION function_name([func_parameter[,...]]) RETURNS type BEGIN ... 函數體 END
示例:建立自定義函數內容稍多,此處先稍微提一下,後面專門章節介紹;
至此,簡單的 DDL 操做介紹完成。
做用:用來操做數據庫中的表對象,主要包括的操做有:INSERT,UPDATE,DELETE
常見的 DML 的基本操做方法以下:
# 給表中添加數據 INSERT INTO ... #修改表中的數據 UPDATE table_name SET ... #刪除表中的數據 DELETE FROM table_name WHERE <condition>; 注:<condition>: 表示 DML 操做時的條件
一、向表中插入數據:
詳細用法:
mysql> INSERT INTO table_name(field1,field2,[,...]) values(value1,value2),(value3,value4),...;
示例:向學生表中插入一條數據,name:’xiaohong’, age:24, gender:’M’ ,以下:
(1)建立表:
mysql> CREATE TABLE student( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL DEFAULT '', age TINYINT, gender ENUM('F','M') ) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
(2)插入數據:
mysql> INSERT INTO student(name,age,gender) VALUES('xiaohong',24,'M'); Query OK, 1 row affected (0.09 sec) mysql> SELECT * FROM student; +----+----------+------+--------+ | id | name | age | gender | +----+----------+------+--------+ | 1 | xiaohong | 24 | M | +----+----------+------+--------+ 1 row in set (0.37 sec)
注:主鍵若是自動遞增,插入時可不用指定;
二、修改表中的數據:
詳細用法:
UPDATE table_name SET field1 = value1, field2 = value2, ... , WHERE <condition>;
示例:將 student 表中 id 爲 1 的記錄中的 name 值修改成:」xiaohua」,以下:
mysql> UPDATE STUDENT SET name = 'xiaohua' WHERE id = 1; Query OK, 1 row affected (0.67 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * FROM student; +----+---------+------+--------+ | id | name| age | gender | +----+---------+------+--------+ | 1 | xiaohua | 24 | M | +----+---------+------+--------+ 1 row in set (0.00 sec)
注意:此處修改的時候,必定得注意加條件,不然整個表都會被改。講個技巧:在 MySQL 的命令中執行操做的時候,能夠在登陸 MySQL 時添加 -U 選項,若是忘加條件,會被阻止執行 sql 語句。登陸命令以下:
[root@WB-BLOG ~]# mysql -uroot -proot -U -h127.0.0.1 -P3306 mysql> UPDATE STUDENT SET name = 'hong'; ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
可見:登陸以後若是不加條件執行 UPDATE 語句,會被阻止;
三、刪除表中的數據:
詳細用法:
mysql> DELETE FROM table_name WHERE <condition>;
示例:刪除 student 表中 id 爲 1 的記錄,以下:
mysql> DELETE FROM student WHERE id = 1; Query OK, 1 row affected (0.37 sec) mysql> SELECT * FROM student; Empty set (0.00 sec)
注意:注意!注意!!再注意!!!,該操做很是危險,命令行中操做時,須要萬分注意。能夠使用登陸時加 -U 參數的方式,防止忘加條件而刪除全部數據,加了 -U 參數以後,若是不加條件,會被阻止,執行結果以下:
mysql> DELETE FROM student; ERROR 1175 (HY000): You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column
至此,DML 操做介紹完畢。
做用:主要用來查看錶中的數據,也是平時使用最多的操做,主要命令爲:SELECT
基本用法以下:
mysql> SELECT fields FROM table_name WHERE <condition>;
注意事項:
fields: 表示要查詢的字段列表,能夠使用代替,可是在程序中最好別寫,由於使用 * 一方面會下降 SQL 的查詢效率,查詢到一些用不到的字段;另外一方面,使用一些 ORM 框架時,若是數據庫中字段有變更,可能會馬上致使程序報錯。
一、簡單不加條件的單表查詢:
用法:
mysql> SELECT * FROM table;
示例略。
二、單表中的條件查詢:
常見的條件:>,>=,<,<= ,=,<>,!=,IN,NOT IN,LIKE,NOT LIKE,REGEXP
示例:
# 查詢年齡大於 23 的記錄 mysql> SELECT * FROM student WHERE age > 23; #查詢年齡大於等於 24 的記錄,和上面 age>23 結果相同 mysql> SELECT * FROM student WHERE age >= 24; #查詢年齡小於 24 的記錄 mysql> SELECT * FROM student WHERE age < 24; #查詢年齡小於等於 24 的記錄 mysql> SELECT * FROM student WHERE age <= 24; #查詢姓名等於 xiaohong 的記錄 mysql> SELECT * FROM student WHERE name = 'xiaohong'; #查詢姓名不等於 xiaohong 的記錄 mysql> SELECT * FROM student WHERE name <> 'xiaohong'; #查詢姓名不等於 xiaohong 的記錄 mysql> SELECT * FROM student WHERE name != 'xiaohong'; #查詢姓名爲 xiaohong 或者 xiaohui 的記錄 mysql> SELECT * FROM student WHERE name in ('xiaohong','xiaohui'); #查詢姓名不是 xiaohong 和 xiaohui 的記錄等價於:where name != xiaohong and name != xiaohui mysql> SELECT * FROM student WHERE name not in ('xiaohong','xiaohui'); #查詢姓名以 xiao 開頭的記錄 mysql> SELECT * FROM student WHERE name like 'xiao%'; #查詢姓名以 xiaohon 開頭的記錄,後面模糊匹配一位,如:xiaohong,xiaohoni mysql> SELECT * FROM student WHERE name like 'xiaohon_'; #查詢姓名中包含 ao 字符創的記錄 mysql> SELECT * FROM student WHERE name like '%ao%'; #查詢以 hong 結尾的記錄 mysql> SELECT * FROM student WHERE name not like '%hong'; #使用正則表達式查詢姓名以 xiao 開頭的記錄 mysql> SELECT * FROM student WHERE name REGEXP('^xiao'); #使用正則表達式查詢姓名以 hong 結尾的記錄 mysql> SELECT * FROM student WHERE name REGEXP('hong$'); #支持的其餘複雜的正則表達式,請參閱資料:
正則表達式教程:http://www.runoob.com/regexp/…
注意:
(1)當某個字段上有索引時,使用上述的反向查詢或者前模糊查詢,如:<>,!=,NOT LIKE,NOT IN,LIKE 「%test」,將會不走索引;
(2)查詢中的潛在問題:若是某個字段在建立表結構的時候未設置非空,則使用 WHERE name!=」BING」的時候,將不會包含 name 爲 NULL 的記錄;
示例:查詢 student 表中年齡大於」xiaohong」年齡的記錄的數量:
mysql> SELECT COUNT(*) FROM student WHERE age > (SELECT age FROM student WHERE name = 'xiaohong'); +----------+ | COUNT(*) | +----------+ |2 | +----------+ 1 row in set (0.46 sec)
三、分頁查詢:
用法:
mysql> SELECT * FROM table_name LIMIT start,num;
參數解釋:
start: 開始位置,默認從 0 開始;
num: 偏移量,即:從開始位置向後查詢的數據條數;
示例:查詢 test 表中,第二頁的數據,每頁顯示 10 條,以下:
mysql> SELECT * FROM student LIMIT 1,10;
四、使用 ORDER BY 對查詢結果進行排序:
用法:
SELECT * FROM table_name <where condition> ORDER BY <field> ASC/DESC;
示例:從 student 表中查詢出全部年齡大於 20 的學生記錄,而且按照年齡 age 倒序排列,以下:
SELECT * FROM student WHERE age > 20 ORDER BY age DESC;
注意:若是在排序時 ORDER BY
五、使用 GROUP BY 對查詢結果集進行分組
基本用法:
mysql> SELECT res FROM table_name <where condition> GROUP BY <field>;
示例:查詢 student 表中男生和女生的數量:
mysql> SELECT gender,COUNT(*) FROM student GROUP BY gender;
六、使用 GROUP BY 以後,在使用 HAVING 完成分組以後的條件查詢
基本用法:
SELECT res FROM table_name <where condition> GROUP BY <field> <having condition>;
示例:查詢 student_course 表中有 3 門成績大於等於 80 的學生學號
(1)建立測試表結構:
mysql> CREATE TABLE student_course(sno INT(11) NOT NULL, cno INT(11) NOT NULL, grade SMALLINT NOT NULL DEFAULT 0 )ENGINE = InnoDB DEFAULT CHARSET = UTF8;
(2)插入測試數據:
INSERT INTO student_course(sno,cno,grade) VALUES(1,100,79); INSERT INTO student_course(sno,cno,grade) VALUES(1,101,89); INSERT INTO student_course(sno,cno,grade) VALUES(1,102,87); INSERT INTO student_course(sno,cno,grade) VALUES(1,103,99); INSERT INTO student_course(sno,cno,grade) VALUES(2,100,90); INSERT INTO student_course(sno,cno,grade) VALUES(2,101,80); INSERT INTO student_course(sno,cno,grade) VALUES(2,102,77); INSERT INTO student_course(sno,cno,grade) VALUES(2,103,79); INSERT INTO student_course(sno,cno,grade) VALUES(3,100,89); INSERT INTO student_course(sno,cno,grade) VALUES(3,101,90); INSERT INTO student_course(sno,cno,grade) VALUES(3,102,83); INSERT INTO student_course(sno,cno,grade) VALUES(3,103,91);
(3)查詢:
mysql> SELECT sno,SUM(CASE WHEN grade > 80 THEN 1 ELSE 0 END) num FROM student_course GROUP BY sno HAVING num >= 3; +-----+------+ | sno | num | +-----+------+ | 1 |3 | | 3 |4 | +-----+------+ 2 rows in set (0.45 sec)
做用:用來授予或回收訪問數據庫的某種特權,並控制數據庫操縱事務發生的時間及效果。
一、GRANT 授予用戶權限:
基本用法:
mysql> GRANT priv_type ON <object_type> TO user <WITH {GRANT OPTION | resource_option} ...>;
示例:給用戶 jerry 授予對 test_db 數據庫的增刪改查權限,容許該用戶從 IP 爲’192.168.0.10’的網絡登陸
(1)方法一:
mysql> GRANT INSERT,SELECT,UPDATE,DELETE ON test_db.* TO 'jerry'@'192.168.0.10' IDENTIFIED BY 'password' WITH GRANT OPTION;
(2)方法二:
mysql> CREATE USER 'jerry'@'192.168.0.10' IDENTIFIED BY 'password'; mysql> GRANT INSERT,SELECT,UPDATE,DELETE ON test_db.* TO 'jerry'@'192.168.0.10';
二、REVOKE 收回用戶權限:
基本用法:
mysql> REVOKE priv_type ON <object_type> FROM 'jerry'@'192.168.0.10';
示例:收回用戶對 test_db 庫的刪除權限:
mysql> REVOKE DELETE ON test_db.* FROM 'jerry'@'192.168.0.10';
三、查看給某個用戶所授予的權限:
基本用法:
mysql> SHOW GRANTS FOR user;
示例:查詢給‘jerry‘@’192.168.0.10’所授予的全部權限:
mysql> SHOW GRANTS FOR 'jerry'@'192.168.0.10';
四、查詢可授予的全部權限,使用技巧:
(1)首先將某個庫 (如:test_db) 的全部權限授予給用戶‘jerry‘@’localhost’
mysql> GRANT ALL ON test_db.* TO 'jerry'@'localhost' IDENTIFIED BY 'jerry';
(2)收回某個權限,如:查詢權限
mysql> REVOKE SELECT ON test_db.* FROM 'jerry'@'localhost';
(3)查看剩餘權限,就能夠查到除了查詢權限以外的權限,再加上查詢權限便可授予的全部權限
mysql> SHOW GRANTS FOR 'jerry'@'localhost';
至此,MySQL 的基本操做 DDL,DML,DQL,DCL 介紹完畢。
上面簡單介紹了一下 MySQL 的基本操做之 DDL、DML、DQL、DCL,在 DDL 中簡單提了一下觸發器,存儲過程和函數,本篇文章將詳細介紹觸發器!
一、觸發器做用:簡單來講,觸發器就是綁定在某個表上的一個特定數據庫對象,當在這個表上發生某種觸發器所監聽的操做時,將會觸發某種動做。
二、觸發器用法:
CREATE TRIGGER trigger_name trigger_event trigger_time ON table_name FOR EACH ROW BEGIN ...trigger_statement... #觸發器的邏輯實現 END
參數解釋:
trigger_name: 觸發器的名稱
trigger_event: 觸發的事件,包括:INSERT,UPDATE,DELETE
trigger_time: 觸發的時間點,包括:BEFORE(事件以前觸發),AFTER(事件以後觸發)
table_name: 觸發器所在表
trigger_statement: 觸發器被觸發以後,所執行的數據庫操做邏輯,能夠爲單一的數據庫操做,或者一系列數據庫操做集合,也能夠包含一些判斷等處理邏輯;
注意:
(1)同一張表中不能同時存在兩個類型同樣的觸發器;
(2)觸發事件和觸發時間點總共能夠組成 3 組 6 種不一樣的觸發器,分別爲:(BEFORE INSERT,AFTER INSERT)、(BEFORE UPDATE,AFTER UPDATE)、(BEFORE DELETE,AFTER DELETE);
(3)觸發事件:
① INSERT:在插入數據的時候觸發,插入數據的動做包括 INSERT,LOAD DATA,REPLACE 操做,即:發生這三種操做時,都會觸發 INSERT 類型的觸發器;
② UPDATE:數據發生變動時觸發,即:發生了 UPDATE 操做;
③ DELETE:從表中刪除某一行的時候觸發,即:發生了 DELETE 或者 REPLACE 操做;
(4)建立觸發器的時候,因爲在觸發器的 trigger_statement 語句中有邏輯,而每一個邏輯都會有結束符,默認爲」;」,故須要在建立以前先定義定界符。防止 SQL 語句在執行以前被存儲引擎(存儲引擎:MySQL 數據庫的插件,後續介紹)解析的時候遇見」;」而提早結束,提示語法錯誤。
三、示例:
(1)示例 1:如今 test_db 中有兩個表,一個爲員工信息表 t_emp,一個爲部門統計表 t_dept_statis,他們的表結構分別以下所示:
員工信息表:
CREATE TABLE t_emp
(
id
INT(11) NOT NULL AUTO_INCREMENT,
name
VARCHAR(50) NOT NULL DEFAULT ‘’, #員工姓名
age
TINYINT(4) DEFAULT NULL, #年齡
gender
ENUM(‘F’,’M’) DEFAULT NULL, #性別
dept_id
INT, #部門編號
PRIMARY KEY (id
)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=UTF8;
部門員工數量統計表:
CREATE TABLE t_dept_statis(
id INT PRIMARY KEY AUTO_INCREMENT,
emp_count INT, #員工數量,初始化爲 0
dept_id INT, #部門編號
update_time DATETIME #更新時間
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
初始化的統計數據,插入兩條統計數據,分別爲編號爲 1 和 2 的兩個部門,初始化員工數量爲 0:
mysql> INSERT INTO t_dept_statis(emp_count,dept_id,update_time) VALUES(0,1,NOW());
mysql> INSERT INTO t_dept_statis(emp_count,dept_id,update_time) VALUES(0,2,NOW());
需求:使用觸發器實現每新增一條員工記錄,部門信息統計表中就能夠自動統計出員工數有變化的部門的員工總數量。這個需求可能不合適,可是徹底能夠說明觸發器的用法:
mysql> d $ #創建定界符,能夠使用」DELIMITER $」,和」d $」等價
mysql> CREATE TRIGGER dep_tri AFTER INSERT ON t_emp FOR EACH ROW
BEGIN
DECLARE num INT;
SET num = (SELECT emp_count FROM t_dept_statis WHERE dept_id = new.dept_id);
UPDATE t_dept_statis SET emp_count = num + 1 ,dept_id = new.dept_id, update_time = now() where dept_id = new.dept_id;
END$
mysql> d ; #從新還原定界符爲默認的定界符」;」
# 查看 t_emp 中的數據,此時是空的
mysql> SELECT FROM t_emp;
Empty set (0.00 sec)
查看 t_dept_statis 中的數據,此時有兩條初始化數據,員工數量爲 0
mysql> SELECT FROM t_dept_statis;
+—-+———–+———+————-+
| id | emp_count | dept_id | update_time |
+—-+———–+———+————-+
| 1 | 0 | 1 | NULL |
| 2 | 0 | 2 | NULL |
+—-+———–+———+————-+
向 t_emp 中插入一條數據,而後查看 t_dept_statis 表,會發現,員工數量會自動統計
mysql> INSERT INTO t_emp(name,age,gender,dept_id) values(‘emp01’,23,’F’,1);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT FROM t_dept_statis;
+—-+———–+———+———————+
| id | emp_count | dept_id | update_time |
+—-+———–+———+———————+
| 1 | 1 | 1 | 2018-05-14 22:51:15 |
| 2 | 0 | 2 | NULL |
+—-+———–+———+———————+
再次向 t_emp 中插入一條數據,而後查看 t_dept_statis 表,會發現,員工數量會再次統計
mysql> INSERT INTO t_emp(name,age,gender,dept_id) values(‘emp03’,26,’M’,2);
Query OK, 1 row affected (0.15 sec)
mysql> SELECT FROM t_dept_statis;
+—-+———–+———+———————+
| id | emp_count | dept_id | update_time |
+—-+———–+———+———————+
| 1 | 1 | 1 | 2018-05-14 22:51:15 |
| 2 | 1 | 2 | 2018-05-14 22:51:30 |
+—-+———–+———+———————+
查看 t_emp 中的數據,會發現目前有兩條記錄,部門 1 和部門二中各有一條,統計表已經經過觸發器實現了員工數量的自動統計:
mysql> SELECT * FROM t_emp;
+—-+——-+——+——–+———+
| id | name | age | gender | dept_id |
+—-+——-+——+——–+———+
| 1 | emp01 | 23 | F | 1 |
| 2 | emp03 | 26 | M | 2 |
+—-+——-+——+——–+———+
2 rows in set (0.00 sec)
(2)示例 2:在 test_db 中有一張用戶表 t_user 和 t_user_bak,表結構相同,以下所示:
mysql> CREATE TABLE t_user(id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL DEFAULT ‘’, #用戶名
age TINYINT NOT NULL DEFAULT 0, #年齡
create_time DATETIME NOT NULL #建立時間
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
mysql> CREATE TABLE t_user_bak(id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL DEFAULT ‘’, #用戶名
age TINYINT NOT NULL DEFAULT 0, #年齡
create_time DATETIME NOT NULL #建立時間
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
建立測試數據,插入以下幾條數據:
mysql> INSERT INTO t_user(name,age,create_time) VALUES(‘name01’,23,NOW());
mysql> INSERT INTO t_user(name,age,create_time) VALUES(‘name02’,25,NOW());
需求:若是 t_user 表中的數據被修改,則將修改前的數據先備份到 t_user_bak 表中,使用觸發器實現:
mysql> d $
mysql> CREATE TRIGGER user_bak_tri BEFORE UPDATE ON t_user FOR EACH ROW
BEGIN
INSERT INTO t_user_bak(name,age,create_time) VALUES(old.name,old.age,NOW());
END$
mysql> d ;
查詢 t_user_bak 表中的數據,此時爲空:
mysql> SELECT FROM t_user_bak;
Empty set (0.00 sec)
修改 t_user 表中 id 爲 1 的數據,而後再次查看 t_user_bak 表中的數據:
mysql> UPDATE t_user SET name = ‘name001’ WHERE name = ‘name01’;
mysql> SELECT FROM t_user_bak;
+—-+——–+—–+———————+
| id | name | age | create_time |
+—-+——–+—–+———————+
| 1 | name01 | 23 | 2018-05-15 05:07:40 |
+—-+——–+—–+———————+
1 row in set (0.00 sec)
可見,數據已經自動備份到 t_user_bak 中。
四、觸發器中的 new 和 old 關鍵字:
(1)做用:用來訪問受觸發器影響的行中的列
(2)用法:
a、在 INSERT 操做中,new 表示將要插入(BEFORE INSERT)或者已經插入(AFTER INSERT)表中的數據;
b、在 UPDATE 操做中,new 表示將要插入或者已經插入的新數據,而 old 表示將要插入或者已經插入的原數據;
c、在 DELETE 操做中,old 表示將要刪除或者已經被刪除的原數據;
d、OLD 是隻讀的,而 NEW 則能夠在觸發器中使用 SET 賦值,這樣不會再次觸發觸發器,形成循環調用;
五、觸發器管理:
(1)查看已經建立好的觸發器:
語法:
mysql> USE db_name; #選擇數據庫
mysql> SHOW TRIGGERS; #查看選擇的數據庫中已經建立的全部觸發器
mysql> SHOW CREATE TRIGGER trigger_name; #查看某個觸發器的建立過程
示例:查看 test_db 庫中已經建立好的全部觸發器:
mysql> USE test_db; #選擇數據庫
mysql> SHOW TRIGGERS G #查看該庫中的觸發器
*** 1. row ***
Trigger: dep_tri
Event: INSERT
Table: t_emp
Statement: BEGIN
DECLARE num INT;
SET num = (SELECT emp_count FROM t_dept_statis WHERE dept_id = new.dept_id);
UPDATE t_dept_statis SET emp_count = num + 1 ,dept_id = new.dept_id, update_time = now() where dept_id = new.dept_id;
END
Timing: AFTER
Created: NULL
sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
Definer: root@127.0.0.1
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
2 rows in set (0.13 sec)
參數解釋:
Trigger:觸發器名稱
Event:觸發器所綁定的事件,即:發生什麼操做時會執行觸發器程序
Table:觸發器所在的表
Statement:觸發器的邏輯
Timing:觸發器的事件
Created:表示建立時間
sql_mode:sql 模式,STRICT_TRANS_TABLES 表示當一個數據不能插入到一個事務表中,則中斷當前操做,NO_ENGINE_SUBSTITUTION 表示編譯的時候若是沒有選擇默認存儲引擎,則會使用一個默認的存儲引擎,並提示一個錯誤;
Definer:建立觸發器的用戶
character_set_client:客戶端使用的字符集
collation_connection:鏈接數據庫使用的字符校驗集
Database Collation:數據庫使用的字符校驗集
除此以外,還能夠使用 information_schema 庫中的 trigger 表查看已經存在的觸發器,以下:
mysql> USE information_schema;
mysql> SELECT TRIGGER_SCHEMA AS ‘db_name’,EVENT_OBJECT_TABLE as ‘table_name’,TRIGGER_NAME as ‘trigger_name’,ACTION_STATEMENT AS ‘trigger_statement’ FROM TRIGGERS G
*** 1. row ***
db_name: test_db
table_name: t_emp
trigger_name: dep_tri
trigger_statement: BEGIN
DECLARE num INT;
SET num = (SELECT emp_count FROM t_dept_statis WHERE dept_id = new.dept_id);
UPDATE t_dept_statis SET emp_count = num + 1 ,dept_id = new.dept_id, update_time = now() where dept_id = new.dept_id;
END
2 rows in set (0.02 sec)
(2)刪除指定的觸發器:
語法:
mysql> DROP TRIGGER trigger_name;
示例:刪除 t_emp 表上的 dep_tri 索引:
mysql> DROP TRIGGER dep_tri;
六、觸發器的優缺點:
優勢:
能夠方便並且高效的維護數據;
缺點:
a、高併發場景下容易致使死鎖,拖死數據庫,成爲數據庫瓶頸,故高併發場景下必定要慎用;
b、觸發器比較多的時候不容易遷移,並且表之間數據導入和導出可能會致使無心中觸發某個觸發器,形成數據錯誤,故對於數據量比較大,並且數據庫模型很是複雜的狀況下慎用;
七、事務場景下的注意要點:
MySQL 中使用了插件式的存儲引擎(存儲引擎後文會詳細介紹),對於 InnoDB 事務型的存儲引擎,若是 SQL 語句執行錯誤,或者觸發器執行錯誤,會發生什麼結果呢?
(1)若是觸發器或者 SQL 語句執行過程當中出現錯誤,則會發生事務的回滾;
(2)SQL 語句若是執行失敗,則 AFTER 類型的觸發器不會執行;
(3)若是 AFTER 類型的觸發器執行失敗,則觸發此觸發器的 SQL 語句將會回滾;
(4)若是 BEFORE 類型的觸發器執行失敗,則觸發此觸發程序的 SQL 語句將會執行失敗;
至此,觸發器相關內容介紹完畢
第 5 章 MySQL 數據庫 DDL 操做之存儲過程和函數
• mysql
保存
標籤:至少 1 個,最多 5 個
mysql×
上篇文章介紹了 MySQL 數據庫 DDL 操做中的觸發器,本章將詳細介紹 MySQL 數據庫 DDL 操做中的存儲過程和函數,存儲過程和函數在某些複雜業務場景下仍是有很大做用的。
一、定義和做用:
存儲過程和函數是數據庫中預先編譯好的一個爲了完成特定功能的 SQL 語句集。經過存儲過程和函數,能夠完成一些具備負責處理邏輯的數據庫操做,同時能夠減小應用程序和數據庫服務器之間的數據傳輸,提高數據庫的數據處理效率。
二、使用存儲過程和函數的前提:
(1)建立存儲過程和函數時,須要用戶具有」CREATE ROUTINE」的權限;
(2)在刪除和修改存儲過程和函數時,須要用戶具有」ALTER ROUTINE」的權限;
(3)在執行存儲過程和函數時,須要用戶具有」EXECUTE」的權限;
三、儲存過程的建立和修改:
(1)存儲過程建立的語法:
CREATE PROCEDURE p_name ([procedure_parameter[,…]])
BEGIN
[characteristic …]
…procedure_statement… #存儲過程的邏輯處理語句
END
參數解釋:
procedure_name:存儲過程的名稱
procedure_parameter:存儲過程的參數,能夠包含多個參數,procedure_parameter 中又包含了存儲過程參數
類型、參數名稱和參數的具體數據類型,它的定義格式爲:[IN|OUT|INOUT] parameter_name field_type
characteristic: 表示要修改存儲過程的哪一個部分,該參數的取值包括如下幾種:
a. CONTAINS SQL,表示子程序包含 SQL 語句,可是,不包含讀或寫數據的語句
b. NO SQL,表示子程序中,不包含 SQL 語句
c. READS SQL DATA,表示子程序中,包含讀數據的語句
d. MODIFIES DATA,表示子程序中,包含寫數據的語句
e. SQL SECURITY {DEFINER | INVOKER},指明誰有權限來執行
DEFINER,表示只有定義者,本身才可以執行
INVOKER,表示調用者能夠執行
f. COMMENT 「conte」,表示註釋信息
g. LANGUAGE SQL,表示存儲過程使用 SQL 語句來實現[默認],爲後期引入其餘語言實現作準備
存儲過程參數類型 [IN|OUT|INOUT] 說明:
IN:表示該參數爲輸入參數,即:調用存儲過程時所要接收的輸入參數,爲一個具體的值
OUT:表示該參數爲輸出參數,即:存儲過程在被調用時,須要接收的一個外部變量,一般使用 @加變量名定義,好比:」@a」。在存儲過程處理完結果以後,能夠將結果放在該外部變量中,供外部查看;
INOUT:表示該參數便可做爲輸入參數,接收一個具體的值;同時也能夠做爲輸出參數,經過傳入外部變量,完成在存儲過程外部查看變量的值;
(2)示例應用:
示例 1:建立一個存儲過程,查詢表出指定表中的記錄數,並能夠在存儲過程外部查看:
修改默認定界符爲 $,也可以使用 DELIMITER 命令完成
mysql> d $
建立存儲過程:
mysql> CREATE PROCEDURE p_count(OUT param INT)
BEGIN
SELECT COUNT() FROM t_user INTO param FROM t_user;
END $
將修改的定界符恢復至默認定界符
mysql> d ;
使用 CALL 命令調用存儲過程,傳入 @a 變量,該變量在存儲過程當中被賦值:
mysql> CALL p_count(@a);
查看經過存儲過程所查詢到的表中記錄數量:
注:查詢自定義變量使用」@< 變量名 >」,若是查詢系統中的變量,能夠使用」@@< 變量名 >」,後期系統參數調優時介紹,此處能夠先了解
mysql> SELECT @a;
+——–+
| @a |
+——–+
| 3 |
+——–+
1 row in set (0.00 sec)
示例 2:建立一個存儲過程,封裝 MySQL 的 LIMIT 函數,實現分頁:
建立存儲過程:
mysql> d $
mysql> CREATE PROCEDURE p_page(IN pageNo INT,IN pageSize INT)
BEGIN
SELECT FROM t_user LIMIT pageNo,pageSize;
END $
mysql> d ;
調用存儲過程,根據具體傳入的值查詢記錄:
mysql> CALL p_page(1,10);
注意:
(1)若是使用的是普通用戶登陸 MySQL 來執行存儲過程,則須要注意權限問題。若是用戶對某個表沒有查詢權限,則該用戶若是調用了某個包含對該表有查詢操做的存儲過程,會調用失敗;
(2)在一個存儲過程當中能夠調用其餘的函數或者存儲過程,如上示例 2,能夠調用系統函數 LIMIT;
(3)在存儲過程當中能夠完成事務的操做,好比:」提交事務 (COMMIT) 和回滾事務 (ROLLBACK)」,可是不能完成」LOAD DATA INFILE」操做;
(3)存儲過程的修改:
目前,存儲過程暫時不支持直接修改其邏輯語句,只支持修改一些存儲過程的特徵,也就是對 characteristic 進行修改。
語法:
ALTER PROCEDURE procedure_name [characteristic …];
示例:對上述的 p_page 存儲過程進行修改,指明調用者能夠執行該存儲過程:
mysql> ALTER PROCEDURE p_page SQL SECURITY INVOKER;
四、函數的建立和修改:
(1)函數建立的語法:
CREATE FUNCTION function_name([function_parameter[,…]])
RETURNS type
BEGIN
[chracteristic …]
…function statement… #函數中的實現邏輯
END
參數解釋:
function_name:函數名稱
function_parameter:函數的參數,它的定義格式爲:」param_name field_type」
[characteristic]:表示要修改的函數的哪一個部分,包括的內容和存儲過程相同
RETURNS type:表示返回值的聲明
(2)示例應用:
示例 1:建立一個函數,對於輸入的內容,會在內容以前拼接」hello」字符串,在結束位置拼接」!」符號,實現以下:
建立函數:
mysql> CREATE FUNCTION function_hello(str CHAR(20))
RETURNS CHAR(50) DETERMINISTIC
RETURN CONCAT(「Hello 「,str,’!’);
調用函數,傳入字符串」Tomcat」,輸出爲:」Hello ,Tomcat!」,以下:
mysql> SELECT function_hello(「Tomcat」);
+————————–+
| function_hello(「Tomcat」) |
+————————–+
| Hello Tomcat! |
+————————–+
1 row in set (0.00 sec)
說明:
RETURNS CHAR(50):表示返回值類型爲 CHAR(50)
RETURN CONCAT(‘Hello ‘,str,’!’):表示具體的返回值是使用 CONCAT 函數拼接獲得的
DETERMINISTIC:指明存儲過程執行的結果是否正確。DETERMINISTIC 表示結果是肯定的。每次執行存儲過程時,相同的輸入會獲得相同的輸出。
示例 2:實現一個加法功能的函數,輸入兩個 INT 類型的值,計算這兩個數的和:
定義函數:
mysql> CREATE FUNCTION function_add1(num1 VARCHAR(20),num2 VARCHAR(20))
RETURNS INT DETERMINISTIC
RETURN (IF(num1 REGEXP 「[0-9]{1,}」,num1,0) + IF(num2 REGEXP 「[0-9]{1,}」,num2,0));
調用,傳入 10 和 20,計算出這兩個數的和爲 30,以下:
mysql> SELECT function_add(10,20);
+———————+
| function_add(10,20) |
+———————+
| 30 |
+———————+
1 row in set (0.00 sec)
注意:該函數中對入參作了簡單判斷,判斷是否爲數值,若是不爲數值,默認當作 0 處理;
(3)函數的修改:
上面修改存儲過程當中介紹了使用 ALTER 完成的方法,此處直接經過修改系統中的 mysql 表中的數據來修改函數,對應的表爲:mysql 庫中的 proc
示例:將 function_hello 函數的定義者修改成」tomcat」@」localhost」。要修改的用戶必須提早存在,修改方式以下:
選庫:
mysql> USE mysql;
修改函數的定義者:
mysql> UPDATE proc SET definer = ‘tomcat@localhost’ WHERE name = ‘function_hello’;
刷新權限,若是不執行該操做,修改的結果不會生效:
mysql> FLUSH PRIVILEGES;
五、存儲過程和函數的查看和刪除:
(1)查看已經建立的存儲過程或者函數:
語法:
SHOW <PROCEDURE|FUNCTION> STATUS LIKE 「pattern」;
參數解釋:
pattern:表示存儲過程或者函數名稱的匹配串,支持模糊匹配
示例 1:查看建立的 p_page 存儲過程:
mysql> SHOW PROCEDURE STATUS LIKE 「p_page」 G
*** 1. row ***
Db: test
Name: p_page
Type: PROCEDURE
Definer: root@127.0.0.1
Modified: 2018-05-16 11:56:56
Created: 2018-05-16 11:21:45
Security_type: INVOKER
Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
示例 2:查看建立的函數」function_hello」:
mysql> SHOW FUNCTION STATUS LIKE ‘%hello’ G
*** 1. row ***
Db: test
Name: function_hello
Type: FUNCTION
Definer: root@127.0.0.1
Modified: 2018-05-16 12:09:17
Created: 2018-05-16 12:09:17
Security_type: DEFINER
Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.01 sec)
(2)查看存儲過程或者函數的定義:
語法:
SHOW CREATE <PROCEDURE|FUNCTION> <procedure_name|function_name>;
示例 1:查看觸發器 p_page 的建立過程:
選庫:
mysql> USE test;
查看建立過程:
mysql> SHOW CREATE PROCEDURE p_page G
*** 1. row ***
Procedure: p_page
sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
Create Procedure: CREATE DEFINER=root
@127.0.0.1
PROCEDURE p_page
(IN pageNo INT,IN pageSize INT)
SQL SECURITY INVOKER
begin
select from t_user limit pageNo,pageSize ;
end
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
示例 2:查看函數 function_hello 的建立過程:
選庫:
mysql> USE test;
查看建立過程:
mysql> SHOW CREATE FUNCTION function_hello G
** 1. row ***
Function: function_hello
sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
Create Function: CREATE DEFINER=root
@127.0.0.1
FUNCTION function_hello
(str CHAR(20)) RETURNS char(50) CHARSET utf8
DETERMINISTIC
RETURN CONCAT(「Hello 「,str,’!’)
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
注意:
查看存儲過程和函數的定義還能夠經過系統庫 information_schema 中的 routines 表來查看,主要包括的字段有:ROUTINE_SCHEMA,ROUTINE_NAME,ROUTINE_BODY,ROUTINE_COMMENT,DEFINER
mysql> SELECT ROUTINE_SCHEMA,ROUTINE_NAME,ROUTINE_BODY,ROUTINE_COMMENT,DEFINER FROM information_schema.routines;
解釋:
ROUTINE_SCHEMA: 存儲過程或者函數所在的庫
ROUTINE_NAME: 存儲過程或者函數名稱
ROUTINE_BODY: 存儲過程或者函數體
ROUTINE_COMMENT: 註釋信息
DEFINER: 存儲過程或者函數的定義者
六、刪除存儲過程和函數:
語法:
DROP <PROCEDURE|FUNCTION> <procedure_name|function_name>;
示例 1:刪除存儲過程 p_page:
mysql> USE test;
mysql> DROP PROCEDURE p_page;
示例 2:刪除函數 function_hello:
mysql> USE test;
mysql> DROP FUNCTION function_hello;
七、變量的定義和賦值:
(1)變量的定義:
語法:
DECLARE var_name type
參數解釋:
var_name: 表示參數名稱
type: 表示參數類型
var_value: 表示參數的默認初始值
示例 1:定義一個 INT 類型的變量 SUM,默認值爲 0:
DECLARE SUM INT DEFAULT 0;
示例 2:定義一個 VARCHAR(20)類型的變量 STR,無初始值:
DECLARE STR VARCHAR(20);
(2)變量的賦值:
語法:
a. 直接經過 SET 賦值:
SET var_name = var_value;
b. 經過 SELECT 查詢到結果以後再賦值:
SELECT
示例 1:給 VARCHAR(20)類型的變量 STR 賦一個初始值爲」」
mysql> SET STR = 「」;
示例 2:查詢表 t_user 中的記錄數量,並將結果賦值給 INT 類型的 STU_COUNT 變量
mysql> SELECT COUNT(*) INTO STU_COUNT FROM t_user;
八、條件定義和處理:
語法:
a. 條件的定義:
DECLARE condition_name CONDITION FOR condition_value;
condition_value:
SQLSTATE sql_state_value
參數解釋:
condition_name: 表示條件的名稱
condition_value: 表示條件中所關注的執行結果,一般爲 SQL 的執行狀態
b. 條件的處理:
DECLARE handler_name HANDLER FOR condition_value do_statement;
參數解釋:
handler_name: 表示處理器的名稱,經常使用的有:」CONTINUE」,」SQLWARNING」,」NOT FOUND」,」SQLEXCEPTION」
condition_value: 表示執行的結果,當處理器匹配到該結果時,會執行後面的 do_statement
示例:在一個存儲過程當中連續給 t_user 表中插入相同的數據,若是插入失敗,則繼續向下執行,而不退出
mysql> d $
mysql> CREATE PROCEDURE p_insert()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE ‘23000’ SET @state = 1;
INSERT INTO t_user(id,name,age) VALUES(1,’bing’,23);
INSERT INTO t_user(id,name,age) VALUES(1,’bing’,23);
SET @val = 666;
END $
mysql> d ;
mysql> SELECT @state,@val;
+——–+——+
| @state | @val |
+——–+——+
| 1 | 666 |
+——–+——+
1 row in set (0.00 sec)
結果分析:在上述的存儲過程當中,第二次插入 t_user 表中的記錄因爲主鍵衝突,故會插入失敗。若是不定義條件處理的話。」SET @val=666」不會被執行,最後查出來的 @val 也不會爲 666,一樣,@state 也不會爲 1,如今查出來的結果分別爲 1 和 666,表示處理器起做用了。主鍵衝突的時候會提示」23000」狀態碼.
九、遊標的使用:
(1)定義:
簡單的理解,遊標就是一個查詢結果集的出口。在這個出口,能夠完成對結果的篩選和其餘操做。
(2)語法:
a. 聲明:
DECLARE cursor_name CURSOR FOR select_statement;
b.OPEN: 打開遊標
OPEN cursor_name;
c.FETCH:將遊標的結果保存到某些中間變量中
FETCH cursor_name INTO var_name,…;
d.CLOSE:關閉遊標
CLOSE cursor_name;
(3)示例:
使用遊標統計出學生表 t_student 中男生和女生的總人數:
建立測試表結構:
CREATE TABLE t_student(
id INT PRIMARY KEY AUTO_INCREMENT,
gender VARCHAR(1) DEFAULT ‘0’ COMMENT 「0- 男,1- 女」,
name VARCHAR(50) DEFAULT ‘’
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
測試數據:
INSERT INTO t_student(gender,name) VALUES(‘1’,’name01’);
INSERT INTO t_student(gender,name) VALUES(‘0’,’name03’);
INSERT INTO t_student(gender,name) VALUES(‘0’,’name06’);
INSERT INTO t_student(gender,name) VALUES(‘0’,’name08’);
建立存儲過程:
mysql> d $
mysql> CREATE PROCEDURE student_count()
BEGIN
DECLARE str VARCHAR(1);
DECLARE gender_str CURSOR FOR SELECT gender FROM t_student;
DECLARE EXIT HANDLER FOR NOT FOUND CLOSE gender_str;
SET @m_count = 0;
SET @f_count = 0;
OPEN gender_str; REPEAT FETCH gender_str INTO str; IF str = '1' THEN SET @m_count = @m_count + 1; ELSE SET @f_count = @f_count + 1; END IF; UNTIL 0 END REPEAT; CLOSE gender_str; END $
mysql> d ;
調用存儲過程:
mysql> CALL student_count();
Query OK, 0 rows affected (0.00 sec)
查看統計結果,M 表示女生數量,F 表示男生數量,可見,已經使用遊標統計完畢:
mysql> SELECT @m_count AS ‘M’,@f_count AS 「F」 FROM DUAL;
+——+——+
| M | F |
+——+——+
| 1 | 3 |
+——+——+
1 row in set (0.00 sec)
十、存儲過程和函數中的流程控制,主要介紹一下經常使用的 IF,CASE,LOOP,REPEAT,WHILE 流程控制:
(1)IF
語法:
IF search_conditoin THEN statement
elseif search_condition THEN state
END IF
示例:已經在上述的遊標中使用到了,可自行查看。
(2)CASE
語法:
CASE case_value
WHEN when_value THEN statement
WHEN when_value THEN statement
… #可有多個判斷語句
ELSE statement
END CASE
示例:將上述判斷學生性別中使用的 IF 改成 CASE 以下:
CASE str
WHEN ‘1’ THEN
SET @m_count = @m_count + 1;
ELSE
SET @f_count = @m_count + 1;
END CASE;
(3)LOOP
語法:
[loop_label:] LOOP
statement
END LOOP [loop_label];
示例:
LOOP 一般用在循環語句中,處於 BEGIN…END 之間,若是沒有退出語句的話,會一直循環下去,形成死循環,能夠和 LEAVE 一塊使用,以下,求 1+2+…+100 的和:
建立存儲過程:
mysql> d $
mysql> CREATE PROCEDURE p_getsum()
BEGIN
SET @sum = 0;
SET @i = 0;
label:LOOP
SET @i = @i + 1;
SET @sum = @sum + @i;
IF @i = 100 THEN
LEAVE label;
END IF;
END LOOP label;
END $
mysql> d ;
調用存儲過程並查看結果:
mysql> CALL p_getsum();
mysql> SELECT @sum;
+——+
| @sum |
+——+
| 5050 |
+——+
1 row in set (0.00 sec)
說明:
LEAVE:一般用在循環結構中,用來退出指定標記的循環,如上」LEAVE label」,表示跳出名稱爲 label 的循環,即:退出 LOOP 循環。
(4)REPEAT
語法:
[label:]REPEAT
statement
UNTIL search_condition
END REPEAT [label]
示例:求 1+2+…+100 的和:
建立存儲過程:
mysql> d $
mysql> CREATE PROCEDURE p_getsum1()
BEGIN
SET @i = 0;
SET @SUM = 0;
REPEAT
SET @i = @i + 1;
SET @sum = @sum + @i;
UNTIL @i > 99
END REPEAT;
SELECT @sum FROM DUAL;
END $
mysql> d ;
調用存儲過程,顯示 1+2+…+100 的值:
mysql> CALL p_getsum1();
+——+
| @sum |
+——+
| 5050 |
+——+
1 row in set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
(5)WHILE
語法:
[label:]WHILE search_condition DO
statement
END WHILE [label];
示例:求 1+2+…+100 的和:
建立存儲過程:
mysql> d $
mysql> CREATE PROCEDURE p_getsum()
BEGIN
SET @i = 0;
SET @sum = 0;
WHILE @i < 100 DO
SET @i = @i + 1;
SET @sum = @sum + @i;
END WHILE;
SELECT @sum FROM DUAL;
END $
d ;
調用存儲過程,查看結果:
CALL p_getsum();
+——+
| @sum |
+——+
| 5050 |
+——+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
此處舉了一個簡單的求和的例子,說明了一下存儲過程當中的流程控制,負責的流程控制也是由這些簡單的組合而成的。簡單的掌握了,就能夠在這個基礎上寫出更復雜的存儲過程。
十一、存儲過程的優缺點:
優勢:
(1)能夠完成實時的複雜報表數據處理及統計;
(2)能夠很好的解決某些業務系統和數據庫之間的耦合度,好比政府、銀行或者金融系統中,一旦存儲過程調試完畢,會穩定運行,減小很大一部分沒必要要的系統間交互;
缺點:
(1)互聯網行業大併發場景,存儲過程會因爲訪問量大,並且同時操做多張表,有可能會形成死鎖,很差排查,致使數據庫出現瓶頸。因此應該慎用,最好別用;
(2)遷移會比較麻煩,若是存儲過程當中用到了多張表,必須先保證表結構遷移正確,不然存儲過程遷移時會出現錯誤;
(3)若是數據庫中的某些表結構變化了,可能須要從新刪除並建立存儲過程,可擴展性較差;
(4)存儲過程多數狀況下都是由 DBA 編寫,普通開發人員不容易掌握;
至此,存儲過程和函數相關的內容介紹完畢
第 6 章 MySQL 數據庫 DDL 操做之事件調度器
MySQL 中的事件調度器是在 5.1 版本以後新增的,能夠在數據庫中定時觸發某種操做,相似於 Spring 中的 Quartz 定時任務或者 Linux 中的 crontab 任務調度器,下面將介紹 MySQL 中事件調度器的用法。
一、調度器的建立:
(1)語法:
CREATE EVENT event_name ON SCHEDULE <time_frequency> DO <event_statement>;
參數解釋:
event_name:表示自定義的事件調度器的名稱,放在 CREATE EVENT 關鍵字以後;
time_frequency:表示該事件調度器什麼時間執行以及執行週期爲多少;
event_statement:表示該事件調度器中要執行的具體操做或者事件,能夠爲一個語句,也能夠爲一個語句塊,即:由 BEGIN…END 包含的語句塊,中間能夠添加一些執行邏輯,須要使用 d 指定定界符。除此以外,還能夠在 event_statement 中調用其餘的存儲過程和函數;
(2)示例:
示例 1:建立一張測試表 t_test,每隔 10 秒鐘向該表中插入一條記錄,操做以下:
建立表結構:
mysql> CREATE TABLE t_test(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10) NOT NULL DEFAULT ‘’,
create_time DATETIME
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
建立事件調度器:
mysql> CREATE EVENT insert_event
ON SCHEDULE EVERY 10 SECOND
DO
INSERT INTO t_test(name,create_time) VALUES(‘test_name’,NOW());
10 秒以後查詢 t_test 表,結果以下:
mysql> SELECT FROM t_test;
Empty set (0.00 sec)
發現並無起做用,10 秒以後並未插入數據,這是因爲事件調度器未打開致使,經過以下命令查看事件調度器的狀態,發現結果爲 OFF,表示未打開:
mysql> SHOW VARIABLES LIKE ‘event_scheduler’;
+—————–+——-+
| Variable_name | Value |
+—————–+——-+
| event_scheduler | OFF |
+—————–+——-+
1 row in set (0.01 sec)
使用以下命令打開事件調度器:
mysql> SET GLOBAL event_scheduler = ON;
或者使用:mysql> SET @@global.event_scheduler = ON;
Query OK, 0 rows affected (0.11 sec)
再次查看,已經打開事件調度器:
mysql> SHOW VARIABLES LIKE ‘event_scheduler’;
+—————–+——-+
| Variable_name | Value |
+—————–+——-+
| event_scheduler | ON |
+—————–+——-+
1 row in set (0.00 sec)
打開事件調度器的開關以後,在通過 10 秒,查看 t_test 表,發現事件調度器已經正常執行了,以下:
mysql> SELECT FROM t_test;
+—-+———–+———————+
| id | name | create_time |
+—-+———–+———————+
| 1 | test_name | 2018-05-16 16:58:45 |
+—-+———–+———————+
注意:上述使用」SET GLOBAL」命令只能全局修改服務器參數,若是數據庫重啓,該參數會失效。若是要永久修改,須要修改 MySQL 的配置文件,編輯 /etc/my.cnf,在 [mysqld] 中添加以下內容:
[mysqld]
event_scheduler = ON #添加該項
…
示例 2:上述示例是每 10 秒給 t_test 表中插入一條記錄,表中的記錄會快速增多,如今經過另一個事件調度器,完成每 1 分鐘清空一次 t_test 表中的記錄,以下:
建立事件調度器:
mysql> CREATE EVENT clear_event
ON SCHEDULE EVERY 1 MINUTE
DO
TRUNCATE TABLE t_test;
建立完成以後,馬上查看,會發現 t_test 表中的數據已經被清空,再 10 秒後差生的數據,在 1 分鐘以後又會被再次清空:
mysql> SELECT FROM t_test;
Empty set (0.00 sec)
示例 3:按期清理 t_log 日誌表,並將清除時間及清除的記錄數量寫入 t_delete_log 中,經過事件調度器和存儲過程實現:
建立 t_delete_log 表:
CREATE TABLE t_delete_log(
id INT PRIMARY KEY AUTO_INCREMENT,
delete_time DATETIME,
delete_count INT DEFAULT 0
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
建立存儲過程:
mysql> d $
mysql> CREATE PROCEDURE p_clear()
BEGIN
DECLARE d_count INT DEFAULT 0;
SET AUTOCOMMIT = 0;
SET d_count = (SELECT COUNT() FROM t_log);
# 判斷是否有待清除的數據 IF d_count > 0 THEN TRUNCATE t_log; INSERT INTO t_delete_log(delete_time,delete_count) VALUES(NOW(),d_count); END IF; COMMIT; END $
mysql> d ;
建立事件調度器:
mysql> CREATE EVENT student_clear_event
ON SCHEDULE EVERY 1 MINUTE
DO
CALL p_clear();
上述事件調度器會每隔 1 分鐘調用一次清除表數據的存儲過程,完成一次歷史數據清理及記錄歸檔,綜合使用到了事件調度器和存儲過程。
二、調度器信息的查看:
語法:
SHOW EVENTS
SHOW CREATE EVENT event_name; #查看指定名稱的調度器的建立信息
SHOW PROCESSLIST; #若是用戶具備 PROCESS 權限,能夠使用該命令查看調度器的線程狀態
SELECT
輸出結果中重要參數說明:
Db: 表示調度器所在的數據庫
Name: 表示調度器的名稱,能夠使用 Like 條件過濾查看
Definer: 表示調度器的定義者
Time zone: 表示調度器使用的時區,SYSTEM 表示使用系統默認的時區
Interval value: 表示調度器時間週期的單位,包括:YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE | DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND
Starts: 表示調度器的開始執時間
Status:表示調度器的可用狀態,包括:ENABLE,DISABLE,ENABLE ON SLAVE
示例 1:查看在 test 庫中建立的事件調度器,能夠發現剛纔建立的調度器器 insert_event 和 clear_event,以下:
mysql> USE test;
mysql> SHOW EVENTS G
*** 1. row
***
Db: test
Name: clear_event
Definer:
root@127.0.0.1
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 1
Interval field: MINUTE
Starts: 2018-05-16 17:08:43
Ends: NULL
Status: ENABLED
Originator: 3
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
*** 2. row
***
Db: test
Name: insert_event
Definer:
root@127.0.0.1
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 10
Interval field: SECOND
Starts: 2018-05-16 16:53:55
Ends: NULL
Status: ENABLED
Originator: 3
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
2 rows in set (0.00 sec)
示例 2:查看觸發器 clear_event 的建立信息:
mysql> USE test;
mysql> SHOW CREATE EVENT clear_event;
*** 1. row
***
Event: clear_event
sql_mode: STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
time_zone: SYSTEM
Create Event: CREATE DEFINER=
root
@
127.0.0.1
EVENT
clear_event
ON SCHEDULE EVERY 1 MINUTE STARTS ‘2018-05-16 17:08:43’ ON COMPLETION NOT PRESERVE ENABLE DO TRUNCATE TABLE t_test
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
示例 3:查看調度器的線程狀態:
mysql> SHOW PROCESSLIST G
*** 1. row
***
Id: 1
User: event_scheduler
Host: localhost
db: NULL
Command: Daemon
Time: 55
State: Waiting for next activation
Info: NULL
三、調度器的修改:
語法:
ALTER
[DEFINER = { user | CURRENT_USER}]
EVENT event_name
[ON SCHEDULE schedule]
[ON COMPLETION [NOT] PRESERVE]
[RENAME TO new_event_name] #修更名稱,支持 RENAME 語法
[ENABLE | DISABLE | DISABLE ON SLAVE] #將其修改成可用或者不可用
[COMMENT ‘string’] #添加註釋信息
[DO event_body]
示例:
示例 1:將 test 庫中的 insert_event 事件調度器更名爲 save_event,操做以下:
mysql> USE test;
mysql> ALTER EVENT insert_event RENAME TO save_event;
mysql> SHOW EVENTS LIKE ‘save_event’G
*** 1. row
***
Db: test
Name: save_event
Definer:
root@127.0.0.1
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 10
Interval field: SECOND
Starts: 2018-05-16 16:53:55
Ends: NULL
Status: ENABLED
Originator: 3
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
# 查看,發現已經修改。
示例 2:將 save_event 調度器改成不可用:
mysql> USE test;
mysql> ALTER EVENT save_event DISABLE;
# 查看 save_event,發現 Status 已經變爲 DISABLE,表示該調度器已經不可用了
mysql> SHOW EVENTS LIKE ‘save_event’G
*** 1. row ***
Db: test
Name: save_event
Definer: root@127.0.0.1
Time zone: SYSTEM
Type: RECURRING
Execute at: NULL
Interval value: 10
Interval field: SECOND
Starts: 2018-05-16 16:53:55
Ends: NULL
Status: DISABLED
Originator: 3
character_set_client: utf8
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
1 row in set (0.00 sec)
# 修改完成以後,再次查看 save_event,已經發現沒有新數據插入了,表示修改生效。
四、調度器的禁用和刪除:
語法:
ALTER EVENT event_name DISABLE; #禁用某個調度器
DROP EVENT [IF EXISTS] event_name; #刪除某個調度器
示例:禁用和刪除 save_event 事件調度器並查看:
mysql> USE test;
# 若是某個調度器不用了,能夠先把其禁用
mysql> ALTER EVENT save_event DISABLE;
# 肯定刪除以後,能夠使用 DROP 完成調度器刪除操做
mysql> DROP EVENT save_event;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW EVENTS LIKE ‘save_event’;
Empty set (0.00 sec)
五、調度器的優缺點及適用場景:
(1)優勢:
a. 能夠實現相似於操做系統層面的定時任務調度;
b. 能夠再數據庫層面解決事件的調度,由 DBA 統一維護,不依賴於操做系統層面的事件調度,有效防止了系統維護人員誤操做調度器而致使的錯誤;
(2)缺點:
a. 在服務器繁忙的狀況下,或者功能對於性能要求很高的狀況下,使用調度器會對性能產生必定影響,由於調度器也是在後臺開啓線程一直在運行及判斷;
b. 須要具備 SUPER 權限的用戶才能夠建立調度器,而 SUPER 用戶權限通常開發人員是不可能具備的,須要 DBA 專門建立;
(3)適用場景:
a. 歷史數據按期統計
b. 過時數據清除
至此,MySQL 事件調度器的內容介紹完畢
第 7 章 MySQL 數據庫之索引的應用
前面幾篇文章詳細介紹了 MySQL 數據庫的 DML,DDL,DCL,DQL 經常使用操做,本篇文章將介紹 MySQL 中一塊對於開發和維護都比較重要的內容–MySQL 索引的應用!
一、索引的做用
(1)若是索引爲惟一索引,能夠保證數據庫中每一行數據的惟一性
(2)索引若是建立的合適,會大幅度提升數據庫的查詢性能,這也是索引最大的做用
(3)索引可以使得在查詢過程當中,使用到數據庫的查詢優化器,極大提升系統的性能
二、索引的分類
(1)按照數據結構和使用的算法劃分:
B+Tree 索引
內部實現採用了 B+Tree 數據結構,數據所有存在葉子節點上。本質上是一棵平衡排序樹,由二叉樹進化而來,各個葉結點由指針相連,按照從左到右的順序讀取葉子結點上的數據,會獲得一個有序的數列。
Hash 索引
內部實現採用了 Hash 算法,數據的保存方式爲一對一,一個鍵對應一條惟一的記錄,相似於 Redis 或者 Memcached 中的 K-V 存儲結構。
R-Tree 索引
內部實現採用了 R-Tree 數據結構,R-Tree 是一種空間索引的數據結構,它是 B 樹向多維空間發展的另一種形式,在地理位置測繪領域有所應用,其餘場景幾乎沒有應用,瞭解便可。
(2)按照類型劃分:
普通索引
普通索引是一種最基本的索引,只是爲了提升數據的查詢效率,也是開發中使用比較多的一種索引,容許索引列重複。
主鍵索引
用來惟一標識數據庫中的一條記錄,經常使用於保證數據庫中記錄的參照完整性,既不可爲空,也不能重複。
惟一索引
用來惟一標識數據庫中的一條記錄,可是與主鍵索引稍有不一樣,惟一索引容許索引列的值爲空,可是不容許索引列的值發生重複。
聯合索引 / 組合索引
指在數據庫表中的某幾個字段上同時創建的索引,即:這個索引會關聯不止一個列。使用的時候須要特別注意,這種索引遵循最左前綴匹配規則,在下面的索引使用中會詳細介紹。
全文索引
用來完成某一段文字中的關鍵字查找,能夠簡單理解爲 like 的增強版,不過使用方法和 like 不一樣,全文索引比較像一個搜索引擎。它目前支持的數據類型有:char,varchar 和 text 類型。
三、索引的建立和查看
(1)索引的建立
語法:
方法一:使用 CREATE INDEX 方法
CREATE
方法二:使用修改表結構的方法
ALTER TABLE table_name ADD
方法三:在建立表的時候指定
CREATE TABLE table_name (
field1 INT NOT NULL AUTO_INCREMENT,
field2 INT ,
field3 INT ,
PRIMARY KEY(field_name),
UNIQUE index_name(field(len)),
INDEX index_name(field(len))
);
示例:
示例 1:建立一張 t_user 測試表,字段包含:[id(主鍵),user_no(用戶編號),login_name(登陸名稱),login_pass(登陸密碼),phone(手機號)],要求:id 做爲主鍵,user_no 列上創建惟一索引,login_name 和 login_pass 兩個列上創建聯合索引,phone 列上創建普通索引:
方法一:建立表的時候指定
mysql> USE test;
mysql> CREATE TABLE t_user(
id INT NOT NULL AUTO_INCREMENT,
user_no VARCHAR(30) NOT NULL,
login_name VARCHAR(50) NOT NULL,
login_pass VARCHAR(50) NOT NULL,
phone VARCHAR(15) NOT NULL,
PRIMARY KEY(id), #主鍵索引
UNIQUE user_no_ind(user_no), #惟一索引
INDEX name_pass_ind(login_name,login_pass), #聯合索引
INDEX phone_ind(phone) #普通索引
)ENGINE = InnoDB DEFAULT CHARSET = UTF8;
方法二:使用 CREATE INDEX 建立索引,此種方式不能建立主鍵索引
mysql> USE test;
# 建立表的時候先不指定索引:
mysql> CREATE TABLE t_user(
id INT NOT NULL AUTO_INCREMENT,
user_no VARCHAR(30) NOT NULL,
login_name VARCHAR(50) NOT NULL,
login_pass VARCHAR(50) NOT NULL,
phone VARCHAR(15) NOT NULL,
PRIMARY KEY (id)
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
# 使用 CREATE INDEX 命令建立表上的索引
mysql> CREATE UNIQUE INDEX user_no_ind ON t_user(user_no);
mysql> mysql> CREATE INDEX name_pass_ind ON t_user(login_name,login_pass);
mysql> CREATE INDEX phone_ind ON t_user(phone);
方法三:使用 ALTER TABLE 修改表結構的方式建立索引
mysql> USE test;
# 建立表結構
mysql> CREATE TABLE t_user(
id INT NOT NULL,
user_no VARCHAR(30) NOT NULL,
login_name VARCHAR(50) NOT NULL,
login_pass VARCHAR(50) NOT NULL,
phone VARCHAR(15) NOT NULL
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
# 使用 ALTER TABLE 命令建立索引
mysql> ALTER TABLE t_user ADD PRIMARY KEY(id);
mysql> ALTER TABLE t_user ADD UNIQUE INDEX user_no_ind(user_no);
mysql> ALTER TABLE t_user ADD INDEX name_pass_ind(login_name,login_pass);
mysql> ALTER TABLE t_user ADD INDEX phone_ind(phone);
示例 2:建立一張帖子內容表,並在帖子內容列建立全文索引
方法一:建立表結構的時候指定索引
mysql> USE test;
mysql> CREATE TABLE t_note(
id BIGINT NOT NULL AUTO_INCREMENT,
note_content TEXT NOT NULL,
create_time DATETIME,
PRIMARY KEY(id),
FULLTEXT(note_content) #添加全文索引
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
方法二:使用 CREATE INDEX 方式建立全文索引
mysql> USE test;
mysql> CREATE TABLE t_note(
id BIGINT NOT NULL AUTO_INCREMENT,
note_content TEXT NOT NULL,
create_time DATETIME,
PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
# 添加全文索引
mysql> CREATE FULLTEXT INDEX note_ind ON t_note(note_content);
方法三:使用 ALTER TABLE 修改表結構的方式建立全文索引
mysql> USE test;
mysql> CREATE TABLE t_note(
id BIGINT NOT NULL AUTO_INCREMENT,
note_content TEXT NOT NULL,
create_time DATETIME,
PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;
# 添加全文索引
mysql> ALTER TABLE t_note ADD FULLTEXT note_ind(note_content);
(2)索引信息的查看
語法:
SHOW INDEX FROM table_name
SHOW INDEXES FROM table_name
注意:SHOW 後面能夠爲 INDEX 或者 INDEXES,能夠使用 WHERE 條件根據索引名稱查看索引信息
示例:查看 t_user 表上所建立的索引
mysql> USE t_user;
mysql> SHOW INDEXES FROM t_user G
*** 1. row
Table: t_user
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
…其餘行略…
輸出字段解釋:
Table:索引所在的表名稱
Non_unique:是否爲非惟一的索引,對惟一索引和主鍵索引,此值爲 0,由於主鍵和惟一鍵必須惟一
Key_name:索引的名稱
Seq_in_index:索引中該列的位置,在
Column_name:索引所在列的列名稱
Collation:列使用哪一種方式存儲在索引中,B+ 數索引老是 A,表示排過序的。對於其餘的如 Hash 索引,此處可能爲 NULL,由於 Hash 索引並未排序
Cardinality:索引中非胃一直的數目的估計值,一般用於優化器去判斷是否查詢時使本索引
Sub_part:是否只是用了列的一部分做爲索引。好比:在某個很是長的字段上的前多少個字符上建立索引的狀況
Packed:關鍵字如何被壓縮,Null 表示未被壓縮
Null:索引的列中是否含有 Null 值,主鍵索引,此處爲空,表示不含有 Null 值
Index_type:索引類型,InnoDB 存儲引擎,此處爲 B+ 樹
Comment:索引列的註釋
Index_comment:索引的註釋
注意:上述字段中,Cardinality 字段相對來講比較重要,能夠經過該字段來判斷當前的索引是否最優,一般若是索引的利用率比較高的話,這個值會比較接近於表中的記錄數,即:和表中的記錄數接近於 1:1,可是這個值並非實時維護,索引當相差比較大的時候,能夠使用」ANALYZE TABLE table_name」命令去更新下這個值,有利於優化器對索引使用的判斷。
四、索引的修改和刪除
(1)索引的刪除
語法:
DROP INDEX index_name ON table_name;
示例:
示例 1:刪除 t_user 表中 phone 列上的 phone_ind 索引
mysql> USE test;
mysql> DROP INDEX phone_ind ON t_user;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
示例 2:刪除 t_user 表中的 id 列上的主鍵索引
mysql> USE test;
mysql> ALTER TABLE t_user DROP PRIMARY KEY;
Query OK, 0 rows affected (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 0
(2)索引的修改
索引的修改過程實際上是先刪除索引,在從新建立索引,能夠按照上述的刪除索引和建立索引步驟完成。
五、索引使用注意事項
(1)使用場景
a. 業務場景中,讀多寫少的場景
b.SQL 查詢場景中,經常使用於 WHERE 語句以後的過濾條件;區分度大於 80%;WHERE 語句以後的過濾字段在過濾時不參與運算;
(2)如下的狀況,對於有索引的列,查詢時也不會使用索引
a. 當優化器判斷使用索引和不適用索引差異不大時,將不會使用索引,好比:性別列建立的索引
b. 查詢條件中發生計算,優化器將不使用索引,好比:WHERE SUBSTR(name,5) = ‘BING’
c. 查詢條件中包含了隱士類型轉換,好比:WHERE phone = 13520277199
d. 反向查詢不會使用索引,好比:!=,<>,NOT IN,NOT LIKE 等,好比:WHERE name != ‘BING’;
e.LIKE 的左模糊匹配,將不會使用索引,好比:WHERE name LIKE ‘%BING’,右匹配查詢會走索引;
f. 聯合索引中,不知足左前綴規則,則 MySQL 不會使用索引。好比:對於 name,pass,user_no 列的聯合索引,下述狀況將不會使用索引:
WHERE pass = ‘value’
WHERE user_no = ‘value’
WHERE pass = ‘123’ AND user_no = ‘123’
而以下的狀況將會使用到索引:
WHERE name = ‘bing’
WHERE name = ‘bing’ AND pass = ‘123’;
WHERE name = ‘bing’ AND user_no = ‘021250’;
WHERE pass = ‘123’ AND name = ‘bing’;
WHERE name = ‘bing’ AND pass = ‘123’ AND user_no = ‘021250’;
g. 某個帶索引的列和不帶索引的列中間使用 OR 鏈接,則帶索引的列也不會使用索引,如:user_no 列帶有索引,phone_未帶索引,則:
不會使用索引:WHERE user_no = ‘123’ OR phone = ‘13520277898’
會使用索引:WHERE user_no = ‘123’ AND phone = ‘15265648758’
h. 若是在聯合索引中有範圍查詢,若是字段之間使用 OR 鏈接,則整個查詢條件不會使用索引,若是字段之間使用 AND 鏈接,則從第一個範圍查詢開始以後的條件都不會使用索引
好比:name,score,usre_no 列上的聯合索引,則:
不會使用索引:WHERE name = ‘bing’ OR score = 123 OR user_no = ‘02311’;
不會使用索引:WHERE name = ‘bing’ AND score = 123 OR user_no = ‘01231’;
會使用索引:WHERE name = ‘bing’ AND score = 123 AND user_no = ‘021321’;
name 列會使用索引,name 以後的列不會使用索引:WHERE name = ‘bing’ AND score > 120 AND user_no = ‘021321’;
六、執行計劃查看
語法:
EXPLAIN
# 從初始化的控制檯日誌判斷是否初始化成功,看到兩個單行的 OK 表示成功,以下
2018-05-22 04:58:48 0 [Note] /usr/local/mysql-5.6.39/bin/mysqld (mysqld 5.6.39-log) starting as process 3642 …
OK
…
2018-05-22 04:58:54 0 [Note] /usr/local/mysql-5.6.39/bin/mysqld (mysqld 5.6.39-log) starting as process 3664 …
OK
# 查看 3306 和 3307 實例的數據目錄是否正常,是否有初始化以後的系統表
[root@WB-BLOG mysql-5.6.39]# ls /mysql_data/3306/data/
ibdata1 ib_logfile0 ib_logfile1 mysql performance_schema test
[root@WB-BLOG mysql-5.6.39]# ls /mysql_data/3307/data/
ibdata1 ib_logfile0 ib_logfile1 mysql performance_schema test
八、使用 mysqld_safe 命令測試實例是否能夠正常啓動
[root@WB-BLOG mysql-5.6.39]# cd bin/
[root@WB-BLOG bin]# ./mysqld_safe –defaults-file=/mysql_data/3306/my.cnf –datadir=/mysql_data/3306/data/ &
# 查看進程是否正常啓動
[root@WB-BLOG bin]# netstat -tunlp | grep mysql
tcp 0 0 :::3306 :::* LISTEN 4050/mysqld
如上結果表示 3306 實例啓動正常,能夠用此方法測試 3307 是否能夠正常啓動。
九、手動編寫針對每一個實例的啓動腳本
(1)修改 3306 和 3307 實例的密碼,修改方式爲使用跳過受權表的方式啓動,而後登錄修改,能夠參考第一篇博文,MySQL 的多種安裝方式中有介紹,使用的命令以下,再也不詳述
[root@WB-BLOG 3306]# /usr/local/mysql-5.6.39/bin/mysqld_safe –defaults-file=/mysql_data/3306/my.cnf –datadir=/mysql_data/3306/data/ –skip-grant-tables &
[root@WB-BLOG ~]# mysql -uroot -p -P3306 -S /mysql_data/3306/data/mysql.sock
mysql> update user set password = password(‘root’);
mysql> flush privileges;
(2)編寫 3306 實例的啓動腳本,以下:
[root@WB-BLOG bin]# cd /mysql_data/3306/
[root@WB-BLOG 3306]# vim mysqld
寫入以下內容:
#!/bin/bash
#
MYSQL_BASE_PATH=/usr/local/mysql-5.6.39
MYSQL_PORT=3306
MYSQL_3306_BASEDIR=/mysql_data/3306
MYSQL_SOCK=${MYSQL_3306_BASEDIR}/data/mysql.sock
MYSQL_CONF=${MYSQL_3306_BASEDIR}/my.cnf
MYSQL_DATADIR=${MYSQL_3306_BASEDIR}/data
MYSQL_USER=root
MYSQL_PASS=root
#When No Input
function Usage(){
echo 「Please Usage ./mysqld {start|stop|restart|status}」
exit 2
}
#Start MySQL
function start_mysql() {
if [ps -ef | grep mysql | grep ${MYSQL_PORT} | grep -v grep | wc -l
-gt 1 ]; then
echo 「MySQL is already running…」
else
${MYSQL_BASE_PATH}/bin/mysqld_safe –defaults-file=${MYSQL_CONF} –datadir=${MYSQL_DATADIR} > /dev/null 2>&1 &
sleep 2
if [ps -ef | grep mysql | grep ${MYSQL_PORT} | grep -v grep | wc -l
-gt 1 ]; then
echo 「MySQL start success!」
else
echo 「MySQL start failure.View logs and try again.」
fi
fi
}
#Stop MySQL
function stop_mysql(){
if [ps -ef | grep mysql | grep ${MYSQL_PORT} | grep -v grep | wc -l
-gt 1 ]; then
${MYSQL_BASE_PATH}/bin/mysqladmin -u${MYSQL_USER} -p${MYSQL_PASS} -P${MYSQL_PORT} -S ${MYSQL_SOCK} shutdown > /dev/null 2>&1 &
sleep 2
if [ps -ef | grep mysql | grep ${MYSQL_PORT} | grep -v grep | wc -l
-gt 1 ]; then
echo 「MySQL stop failure…」
else
echo 「MySQL stop success!」
fi
else
echo 「MySQL is not running…」
fi
}
#Restart MySQL
function restart_mysql(){
stop_mysql
sleep 2
start_mysql
}
#MySQL status
function mysql_status(){
if [ps -ef| grep mysql | grep ${MYSQL_PORT}|grep -v grep | wc -l
-gt 1 ]; then
echo 「MySQL is running…」
else
echo 「MySQL is stopped.」
fi
}
case $1 in
start)
start_mysql
;;
stop)
stop_mysql
;;
restart)
restart_mysql
;;
status)
mysql_status
;;
*)
Usage
;;
esac
授予 mysqld 腳本可執行權限,而後啓動:
[root@WB-BLOG 3306]# chmod +x mysqld
[root@WB-BLOG 3306]# ./mysqld start
# 查看運行狀態
[root@WB-BLOG 3306]# ./mysqld status
MySQL is running…
(3)將 3306 實例中的 mysqld 腳本拷貝一份到 /mysqld_data/3307 目錄下,而後修改端口及實例的目錄,最終內容以下:
#!/bin/bash
#
MYSQL_BASE_PATH=/usr/local/mysql-5.6.39
MYSQL_PORT=3307
MYSQL_3307_BASEDIR=/mysql_data/3307
MYSQL_SOCK=${MYSQL_3307_BASEDIR}/data/mysql.sock
MYSQL_CONF=${MYSQL_3307_BASEDIR}/my.cnf
MYSQL_DATADIR=${MYSQL_3307_BASEDIR}/data
MYSQL_USER=root
MYSQL_PASS=root
#When No Input
function Usage(){
echo 「Please Usage ./mysqld {start|stop|restart|status}」
exit 2
}
#Start MySQL
function start_mysql() {
if [ps -ef | grep mysql | grep ${MYSQL_PORT} | grep -v grep | wc -l
-gt 1 ]; then
echo 「MySQL is already running…」
else
${MYSQL_BASE_PATH}/bin/mysqld_safe –defaults-file=${MYSQL_CONF} –datadir=${MYSQL_DATADIR} > /dev/null 2>&1 &
sleep 2
if [ps -ef | grep mysql | grep ${MYSQL_PORT} | grep -v grep | wc -l
-gt 1 ]; then
echo 「MySQL start success!」
else
echo 「MySQL start failure.View logs and try again.」
fi
fi
}
#Stop MySQL
function stop_mysql(){
if [ps -ef | grep mysql | grep ${MYSQL_PORT} | grep -v grep | wc -l
-gt 1 ]; then
${MYSQL_BASE_PATH}/bin/mysqladmin -u${MYSQL_USER} -p${MYSQL_PASS} -P${MYSQL_PORT} -S ${MYSQL_SOCK} shutdown > /dev/null 2>&1 &
sleep 2
if [ps -ef | grep mysql | grep ${MYSQL_PORT} | grep -v grep | wc -l
-gt 1 ]; then
echo 「MySQL stop failure…」
else
echo 「MySQL stop success!」
fi
else
echo 「MySQL is not running…」
fi
}
#Restart MySQL
function restart_mysql(){
stop_mysql
sleep 2
start_mysql
}
#MySQL status
function mysql_status(){
if [ps -ef| grep mysql | grep ${MYSQL_PORT}|grep -v grep | wc -l
-gt 1 ]; then
echo 「MySQL is running…」
else
echo 「MySQL is stopped.」
fi
}
case $1 in
start)
start_mysql
;;
stop)
stop_mysql
;;
restart)
restart_mysql
;;
status)
mysql_status
;;
*)
Usage
;;
esac
十、單機多實例的登陸
(1)常規登陸方法
[root@WB-BLOG ~]# mysql -uroot -proot -h127.0.0.1 -P3307 -S /mysql_data/3307/data/mysql.sock
參數解釋:
-S: 指定示例對應的 Socket 文件
注意:單機多實例的登陸須要指定待登陸示例對應的 socket 文件。
(2)爲了防止每次登錄 MySQL 時須要帶一對參數,編寫一個方便登錄的腳本 mysql_login.sh,將登陸所需參數寫入到腳本中,內容以下:
[root@WB-BLOG mysql_data]# cat mysql_login.sh
#!/bin/bash
#
SERVER_IP=127.0.0.1
MYSQL_BASE_PATH=/usr/local/mysql-5.6.39
MYSQL_01_PORT=3306
MYSQL_02_PORT=3307
#MYSQL USER AND PASS
MYSQL_01_USER=root
MYSQL_01_PASS=root
MYSQL_02_USER=root
MYSQL_02_PASS=root
MYSQL_01_BASEDIR=/mysql_data/3306
MYSQL_02_BASEDIR=/mysql_data/3307
MYSQL_01_SOCK=${MYSQL_01_BASEDIR}/data/mysql.sock
MYSQL_02_SOCK=${MYSQL_02_BASEDIR}/data/mysql.sock
echo 「1> mysql-3306」
echo 「2> mysql-3307」
read -p 「Please Input the Login Server Number:[1,2]:」 INPUT
case $INPUT in
1)
${MYSQL_BASE_PATH}/bin/mysql -u${MYSQL_01_USER} -p${MYSQL_01_PASS} -P${MYSQL_01_PORT} -h${SERVER_IP} -S ${MYSQL_01_SOCK} –prompt=’mysql-server-3306> ‘
;;
2)
${MYSQL_BASE_PATH}/bin/mysql -u${MYSQL_02_USER} -p${MYSQL_02_PASS} -P${MYSQL_02_PORT} -h${SERVER_IP} -S ${MYSQL_02_SOCK} –prompt=’m
ysql-server-3307> ‘
;;
*)
echo 「Wrong Input.Please run mysql_login.sh again.」
;;
esac
腳本中的登陸命令參數說明:
prompt: 指定登陸以後的 mysql 命令行提示符,若是同時打開多個 shell 窗口,能夠在每個 mysql 的命令行窗口指定命令提示符,防止數據庫的誤操做。
腳本的運行效果:
[root@WB-BLOG mysql_data]# ./mysql_login.sh
1> mysql-3306
2> mysql-3307
Please Input the Login Server Number:[1,2]:1
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 4
Server version: 5.6.39-log MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type ‘help;’ or ‘h’ for help. Type ‘c’ to clear the current input statement.
mysql-server-3306>
# 登陸成功
至此,MySQL 的多實例搭建介紹完畢,後面的主從異步複製介紹打算使用 MySQL 單機多實例來部署,
第 9 章 MySQL 數據庫運維之主從複製搭建
上篇文章詳細介紹了 MySQL 數據庫的單機多實例搭建,本篇文章將在上篇文章的基礎上介紹 MySQL 主從複製過程,其中常見的複製架構有:異步複製,半同步複製及同步複製。經常使用的複製架構有異步複製及半同步複製!
1、常見的複製架構
一、主主複製
(1)結構圖:
(2)說明:主主複製即複製的兩個實例互爲主從,兩個庫中均可以同時讀和寫;
(3)優勢:
a、對於讀寫請求都較多的需求,能夠在多個實例之間分攤讀寫請求,減輕單實例的讀寫壓力
b、互爲主從,當一個示例出故障時,能夠迅速切換到另一個實例上,提供讀寫服務
二、一主一從
(1)結構圖:
(2)說明:指的是在兩個數據庫實例中,一個實例扮演着主庫的角色,另外一個實例扮演着從庫的角色。這種方案中,從庫一般用來做爲備份使用,提供服務的多爲主庫;
(3)優勢:
a、多數狀況下,能夠有效下降因某臺數據庫服務器故障而致使數據丟失的機率
b、做爲備份服務器,能夠在從庫上完成在線數據的全備份,而不影響主庫的寫服務
三、一主多從
(1)結構圖:
(2)說明:指的是在多個數據庫實例中,只包含了一個主庫,其餘實例都做爲該主庫的從庫,這種架構是業務規模較大場景中的一種複製架構;
(3)優勢:
a、該方已經比較成功,並且使用範圍極爲普遍,出問題以後能夠迅速找到解決方案
a、做爲主庫的備份,能夠迅速擴展多個從庫
b、能夠使用 mysql-proxy 等中間件提供讀寫分離服務,經過多個從庫來應對大量的讀請求,提升網站的吞吐量
c、當主庫出故障時,從庫能夠快速接管主庫,成爲新的主庫,提供寫服務
2、主從複製的原理和過程
一、主從異步複製的原理
主庫上的二進制 bin-log 中記錄主庫的全部 DML 操做,同時在主庫上運行有一個 IO 線程,用於響應從庫上的 bin-log 日誌讀取請求;在從庫上運行有一個 IO 線程和一個 SQL 線程,IO 線程會實時經過網絡請求去從庫上讀取 bin-log 日誌,而後寫入到自身的 relay-log 日誌文件中,同時運行在從庫上的 SQL 線程會去解析並讀取 relay-log,而後在自身庫上執行讀取到的 SQL,完成主從數據的同步,示意圖以下:
二、主從同步的工做過程
(1)詳細過程
a、主庫上會開啓了二進制 bin-log 日誌記錄,同時運行有一個 IO 線程;
b、主庫上對於須要同步的數據庫或者表所發生的全部 DML 操做都會被記錄到 bin-log 二進制日誌文件中;
c、從庫上開啓 relay-log 日誌,同時運行有一個 IO 線程和一個 SQL 線程;
d、IO 線程負責從主庫中讀取 bin-log 二進制日誌,並寫入到本地的 relay-log 日誌中,同時記錄從庫所讀取到的主庫的日誌文件位置信息,以便下次從這個位置點再次讀取;
e、SQL 線程負責從本地的 relay-log 日誌中讀取同步到的二進制日誌,並解析爲數據庫能夠識別的 SQL 語句,而後應用到本地數據庫,完成同步;
f、執行完 relay-log 中的操做以後,進入睡眠狀態,等待主庫產生新的更新;
(2)以上詳細過程可總結爲三步
第一步:主庫在每一個事務更新數據完成以前,將該操做記錄串行地寫入到 binlog 文件中;
第二步:從庫開啓一個 I/O 線程,該線程對主庫打開一個普通鏈接,主要工做是讀取二進制日誌。若是讀取的進度已經跟上了主庫,就進入睡眠狀態並等待主庫產生新的事件。I/O 線程最終的目的是將這些事件寫入到中繼日誌中;
第三步:SQL 線程會讀取中繼日誌,並順序執行該日誌中的 SQL 事件,從而與主數據庫中的數據保持一致;
3、MySQL 異步複製搭建過程(單機多實例介紹,沿用上篇文章中搭建的多實例環境)
一、環境準備
操做系統:CentOS6.9
服務器 IP:192.168.0.10
數據庫版本:MySQL-5.6.39
數據庫實例:實例 1–3306 端口(主),實例 2–3307 端口(從)
二、編輯 3306 實例的配置文件,打開該實例的二進制日誌,並修改 server-id,以下
[root@WB-BLOG ~]# cd /mysql_data/3306/
[root@WB-BLOG 3306]# vim my.cnf
[mysqld]
server_id=3
log_bin=/mysql_data/3306/data/mysql-bin
log_bin_index=/mysql_data/3306/data/mysql-bin-index
binlog_format=mixed
…
參數解釋:
(1)server-id:用來標識一個惟一的實例,若是是在同一個局域網內,能夠使用 ip 地址的最後一段,要保證惟一
(2)log_bin:二進制日誌文件的路徑,mysql 用戶對該路徑必須具備讀寫權限
(3)log_bin_index:二進制文件的索引路徑,mysql 用戶對該路徑必須具備讀寫權限
(4)binlog_format:表示二進制日誌內容的記錄方式,有三種方式:
a、row: 基於行記錄的方式,MySQL 會將真實發生變化的行記錄進日誌,因此若是有 update 更新全表的操做,二進制日誌文件會變得很是大。一般用於 SQL 語句複雜可是影響的行比較少的場景
b、statement: 基於語句的方式,MySQL 會將致使數據發生變化的 SQL 語句記錄到日誌文件中,適用於一條語句影響不少行的場景,可是注意當在主庫上使用到了 UUID,SYSDATE,FOUND_ROWS 函數時,使用 statement 方式的複製會出現主從不一致的狀況;
c、mixed: 混合記錄模式,MySQL 會自動進行判斷具體是使用 row 格式仍是 statement 格式,一般狀況下都使用 mixed,由 MySQL 來進行判斷
三、重啓主庫
[root@WB-BLOG ~]# cd /mysql_data/3306/
[root@WB-BLOG 3306]# ./mysqld restart
四、備份主庫的數據
[root@WB-BLOG 3306]# cd /usr/local/mysql-5.6.39/bin/
[root@WB-BLOG tmp]# ./mysqldump -uroot -proot -h127.0.0.1 -P3306 -S /mysql_data/3306/data/mysql.sock -A –master-data=2 -F –single-transaction | gzip > /tmp/mysql_all.sql.gz
參數說明:
-S:指定 socket 文件,單機多實例必需要指定
-A:–all-databases,表示備份全部的數據庫
–master-data:表示 change master 命令是否包括在備份以後的 sql 文件中,經常使用的值有 1 和 2
1:表示 change master 指令在 sql 文件中處於打開狀態,可用於快速建立主從同步,不用再次手動修改日誌文件名稱和位置點
2:表示 change master 指令在 sql 文件中會被註釋,從庫上使用 change master 時須要手動指定日誌文件的文件名和位置點
-F:表示備份日誌的時候刷新二進制日誌,從新建立一個新的二進制日誌文件
–single-transaction:用於 InnoDB 存儲引擎格式的表備份,導出開始時設置事務隔離狀態並使用一致性快照開始事務,然後立刻執行 unlock tables,而後執行導出
gzip:表示將備份的 sql 文件壓縮
# 其餘常見參數在後面的 MySQL 數據備份於恢復會詳細介紹
五、登錄主庫,而後建立複製帳戶
[root@WB-BLOG 3306]# cd ..
[root@WB-BLOG mysql_data]# ./mysql_login.sh
mysql-server-3306> USE mysql
# 受權從庫的
mysql-server-3306> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON . to ‘repl‘@’127.0.0.1’ IDENTIFIED BY ‘repl’;
mysql-server-3306> FLUSH PRIVILEGES;
六、查看主庫的二進制日誌文件及位置點
mysql-server-3306> show master status G
*** 1. row ***
File: mysql-bin.000014
Position: 367
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
七、將主庫導出的數據導入從庫中
[root@WB-BLOG mysql_data]# cd /usr/local/mysql-5.6.39/bin/
[root@WB-BLOG bin]# gzip -d /tmp/mysql_all.sql.gz | ./mysql -uroot -proot -S /mysql_data/3307/data/mysql.sock
八、修改從庫的配置文件,開啓 relay-log 日誌,並設置 server-id,以下
[mysqld]
server-id=4
relay_log=/mysql_data/3307/data/relay-log
relay_log_index = /mysql_data/3307/data/relay-log-index
…
九、修改從庫上的 master 指向,使其指向主庫,而且從主庫上最新的二進制日誌和位置點開始同步,而後啓動主從同步
[root@WB-BLOG mysql_data]# ./mysql_login.sh
mysql-server-3307> CHANGE MASTER TO master_host = ‘127.0.0.1’,master_port = 3306,master_user=’repl’,master_password=’repl’,master_log_file=’mysql-bin.000014’,master_log_pos = 367;
mysql-server-3307> START SLAVE;
mysql-server-3307> SHOW SLAVE STATUS G
*** 1. row ***
Slave_IO_State: Waiting for master to send event
Master_Host: 127.0.0.1
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000015
Read_Master_Log_Pos: 425
Relay_Log_File: relay-log.000004
Relay_Log_Pos: 588
Relay_Master_Log_File: mysql-bin.000015
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
注意:上述結果中 Slave_IO_Running 和 Slave_SQL_Running 都爲 Yes 表示主從同步成功,若是爲 Connecting…,能夠等待一會再次查看,若是爲 No,表示同步失敗;
參數說明:
master_host: 主庫的主機名或者 IP 地址
master_port: 主庫的端口號,必須爲整數,不能加引號,不然會提示錯誤
master_user: 在主庫上添加的複製用戶名稱
master_password: 在主庫上添加的複製用戶密碼
master_log_file: 主庫當前的二進制日誌文件名稱
master_log_pos: 主庫當前的二進制文件位置點,整數,不可加引號,不然會提示錯誤
開啓主從的另一種方法是分別開啓 SQL 線程和 IO 線程,以下:
mysql> START SLAVE IO_THREAD;
mysql> START SLAVE SQL_THREAD;
十、驗證,登錄主庫,而後建立數據庫,查看從庫是否能夠正常同步
mysql-server-3306> CREATE DATABASE test_db;
mysql-server-3306> QUIT
mysql-server-3307> SHOW DATABASES;
+——————–+
| Database |
+——————–+
| information_schema |
| mysql |
| performance_schema |
| test |
| test_db |
+——————–+
5 rows in set (0.00 sec)
# 從上面的結果能夠看到,test_db 已經同步到 3307 實例上了
十一、至此,MySQL 的主從複製搭建完畢。
十二、主從同步中常見的問題
(1)從庫的 IO 線程沒法鏈接,經過」show slave status G」能夠查看到具體的錯誤信息
緣由 1:在主庫上建立的用戶受權錯誤,致使從庫沒法遠程鏈接主庫
解決辦法 1:在主庫上經過」show grants for ‘user‘@’ip’;」查看受權是否正確,若是錯誤,從新受權便可
緣由 2:若是是獨立主機上的兩個主從數據庫實例,受權正確的狀況下,多是因爲主庫的防火牆攔截致使從庫沒法鏈接主庫
解決辦法 2:關閉主庫的防火牆,或者在主庫所在服務器添加防火牆規則,容許從庫的 tcp 鏈接
(2)從庫啓動的時候提示 server-id 衝突,致使沒法同步主庫上的數據
緣由:主從庫配置文件中的 server-id 相同了
解決辦法:將主庫可從庫配置文件中的 server-id 改成不一樣,從新開啓從庫上的同步便可
(3)在從庫上執行了建立庫或者表的操做,而後在主庫上又執行了一遍,致使同步錯誤,以下:
Last_SQL_Error: Error ‘Can’t create database ‘test1’; database exists’ on query. Default database: ‘test1’. Query: ‘create database test1’
緣由:從庫上建立了庫,主庫上再次建立,從庫會將主庫上的建立過程再次應用到從庫,致使從庫上建立同名的庫,發生錯誤
解決辦法:中止從庫,而後設置 sql_slave_skip_count,使其跳過同步主庫建立庫的操做,從下一個操做開始同步,以下:
# 中止從庫
mysql-server-3307> STOP SLAVE;
Query OK, 0 rows affected (0.00 sec)
# 向前跳躍一步,從下一個點開始同步
mysql-server-3307> SET GLOBAL sql_slave_skip_counter =1;
Query OK, 0 rows affected (0.00 sec)
# 從新開啓從庫上的同步
mysql-server-3307> START SLAVE ;
Query OK, 0 rows affected (0.03 sec)
# 再次查看,發現已經正常
針對直接寫從庫的操做,能夠再從庫上建立一個普通用戶,授予其部分操做權限,而後設置從庫的只讀,經過在從庫的配置文件中增長」read-only」參數來設置。可是注意,這個參數對並且只對非 super 用戶生效,對 root 用戶沒有任何效果。
1三、再生產場景下如何保證主庫上的用戶能夠有寫權限,從庫上的用戶只有讀權限
方法 1:在設置從庫同步的時候,排除對 mysql 系統庫的同步,經過在配置文件中指定 binlog_ignore_db=mysql 來排除不須要同步的庫,或者在配置文件中指定 binlog_do_db=db_name 只來同步須要同步的庫,而後分別在主庫上建立能夠寫的用戶,在從庫上建立只能讀的用戶;
[mysqld]
binlog_ignore_db=mysql
binlog_do_db=user_db
方法 2:在未排除任何庫的狀況下,先在主庫上建立能夠讀寫的用戶,而後在從庫中重新回收用戶的寫權限;
方法 3:在主庫和從庫上建立不一樣的用戶,而後分別授予不一樣的權限,使得主庫只能寫,從庫只能讀;
4、MySQL 半同步搭建過程(介紹過程仍然使用單機多實例的環境)
一、定義
是介於異步複製和全同步複製之間的一種複製方式,主庫在執行完客戶端提交的事務後不是馬上返回給客戶端,而是等待至少一個從庫接收到並寫到 relay log 中才返回給客戶端。
二、優缺點
(1)優勢:有效的提升了數據的安全性,須要等到數據寫到從庫以後才返回給客戶端;
(2)缺點:由於須要等待至少一個從庫接收到並寫入 relaylog 中,索引會形成必定的網絡延遲,須要在網絡延遲較低的環境中使用
三、搭建過程
(1)前提條件:
a、MySQL 數據庫版本爲 5.5 及以上
b、屬性變量 have_dynamic_loading 的值爲 YES
c、異步複製已經搭建完成
(2)查看主庫和從庫上的 have_dynamic_loading 變量
[root@WB-BLOG mysql_data]# ./mysql_login.sh
mysql-server-3306> SHOW VARIABLES LIKE ‘have_dynamic_loading’;
+———————-+——-+
| Variable_name | Value |
+———————-+——-+
| have_dynamic_loading | YES |
+———————-+——-+
1 row in set (0.00 sec)
(3)登錄主庫,在主庫上安裝半同步插件
mysql-server-3306> INSTALL PLUGIN rpl_semi_sync_master SONAME ‘semisync_master.so’;
Query OK, 0 rows affected (0.01 sec)
mysql-server-3306> SHOW PLUGINS G
*** 43. row ***
Name: rpl_semi_sync_master
Status: ACTIVE
Type: REPLICATION
Library: semisync_master.so
License: GPL
43 rows in set (0.00 sec)
# 查看輸出結果中包括上面的一行,表示半同步插件安裝成功
注:若是想卸載半同步插件,能夠使用以下命令:
mysql-server-3306> UNINSTALL PLUGIN rpl_semi_sync_master;
(4)登錄從庫,安裝從庫上的半同步插件
mysql-server-3307> INSTALL PLUGIN rpl_semi_sync_slave SONAME ‘semisync_slave.so’;
Query OK, 0 rows affected (0.01 sec)
mysql-server-3307> SHOW PLUGINS;
*** 43. row ***
Name: rpl_semi_sync_slave
Status: ACTIVE
Type: REPLICATION
Library: semisync_slave.so
License: GPL
43 rows in set (0.01 sec)
注:從庫上的半同步插件,也能夠使用以下命令完成卸載:
mysql-server-3307> UNINSTALL PLUGIN rpl_semi_sync_slave;
(5)查看插件是否加載成功
主庫:
mysql-server-3306> SELECT plugin_name,plugin_status FROM information_schema.plugins WHERE plugin_name LIKE ‘%semi%’;
+———————-+—————+
| plugin_name | plugin_status |
+———————-+—————+
| rpl_semi_sync_master | ACTIVE |
+———————-+—————+
1 row in set (0.00 sec)
從庫:
mysql-server-3307> SELECT plugin_name,plugin_status FROM information_schema.plugins WHERE plugin_name LIKE ‘%semi%’;
+———————+—————+
| plugin_name | plugin_status |
+———————+—————+
| rpl_semi_sync_slave | ACTIVE |
+———————+—————+
1 row in set (0.00 sec)
(6)配置並開啓主庫的半同步複製,而後重啓主庫
[root@WB-BLOG 3306]# vim my.cnf
# 在 mysqld 段下面添加以下內容:
[mysqld]
plugin-load = rpl_semi_sync_master=semisync_master.so
rpl_semi_sync_master_enabled=1
[root@WB-BLOG 3306]# ./mysqld restart
(7)配置並開啓從庫的半同步複製,而後重啓從庫
[root@WB-BLOG 3307]# vim my.cnf
# 添加以下內容:
[mysqld]
plugin-load = rpl_semi_sync_slave=semisync_slave.so
rpl_semi_sync_slave_enabled=1
[root@WB-BLOG 3307]# ./mysqld restart
(8)重啓從庫上的 IO 線程
mysql-server-3307> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
ysql-server-3307> START SLAVE IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
(9)查看主庫和從庫上的半同步複製是否在運行
登陸主庫查看:
mysql-server-3306> SHOW STATUS LIKE ‘rpl_semi_sync_master_status’;
+—————————–+——-+
| Variable_name | Value |
+—————————–+——-+
| Rpl_semi_sync_master_status | ON |
+—————————–+——-+
登陸從庫查看:
mysql-server-3307> SHOW STATUS LIKE ‘rpl_semi_sync_slave_status’;
+—————————-+——-+
| Variable_name | Value |
+—————————-+——-+
| Rpl_semi_sync_slave_status | ON |
+—————————-+——-+
1 row in set (0.00 sec)
上述結果表示主庫和從庫上的半同步複製運行正常。
(10)驗證半同步複製是否正常
驗證方法:正常在主庫上建立一張表,會馬上返回,耗時 0.1s。關閉從庫的 io 線程,而後在主庫上執行建表操做,會發現,主庫上回阻塞 10 秒以後纔會返回,而這個時間正好和主庫上的 rpl_semi_sync_master_timeout 相同,表示半同步起做用了,主庫的 DDL 操做須要等到從庫應用完 relaylog 以後才返回;
# 主庫執行:
mysql-server-3307> STOP SLAVE IO_THREAD;
# 從庫執行:
mysql-server-3306> CREATE TABLE test(id int);
Query OK, 0 rows affected (10.03 sec)
# 查看主庫上的 rpl_semi_sync_maser_timeout
mysql-server-3306> SHOW VARIABLES LIKE ‘rpl_semi_sync_master_timeout’;
+——————————+——-+
| Variable_name | Value |
+——————————+——-+
| rpl_semi_sync_master_timeout | 10000 |
+——————————+——-+
至此,MySQL 的半同步複製搭建完成。
四、半同步搭建中常見問題
(1)主從不能正常同步:和主從同步沒法正常複製的排查方法相同
(2)不能正常安裝半同步插件
緣由 1:多是版本問題
解決辦法 1:查看 MySQL 實例的版本,若是版本問題,更換新版本從新安裝便可
mysql> SELECT version();
緣由 2:MySQL 的安裝目錄中未包含用於半同步複製的共享庫
解決辦法 2:找到該版本對應的半同步共享庫,而後從新安裝
5、全同步複製
同步複製在全部複製方案中最安全,可是性能最差,並且須要使用 DRBD(分佈式複製塊設備)來完成數據的同步,DRBD 是一種相似於」rsync+inotify」的架構,一般使用較少,幾乎不用,此處不作詳細介紹。
到此,MySQL 的主從複製介紹完畢,主從複製是一塊很大的內容,包括延遲排查,數據一致問題、快速主從搭建及主從複製的高可用,後面會繼續寫
第 10 章 MySQL 數據庫運維之主從複製延遲問題排查
上篇文章介紹了單機環境下的 MySQL 主從異步複製和主從半同步複製的搭建過程。搭建過程很簡單,可是在實際使用過程當中,更多的是解決問題,本篇文章將介紹一下 MySQL 主從複製中常見的問題以及如何定位問題和如何解決問題。
1、從庫複製延遲問題
一、可能的緣由以下
(1)主從服務器處於不一樣的網絡之中,因爲網絡延遲致使;
(2)主從服務器的硬件配置不一樣,從服務器的硬件配置(包括內存,CPU,網卡等)遠低於主服務器;
(3)主庫上有大量的寫入操做,致使從庫沒法實時重放主庫上的 binlog;
(4)主庫上存在着大事務操做或者慢 SQL,致使從庫在應用主庫 binlog 的過程過慢,造成延遲;
(5)數據庫實例的參數配置問題致使,如:從庫開啓了 binlog,或者配置了每次事務都去作刷盤操做;
二、主從同步延遲問題判斷
(1)根據從庫上的狀態參數判斷
mysql-server-3307> SHOW SLAVE STATUS G
在輸出結果中找到 Seconds_Behind_Master 參數,這個參數表示的是從庫上的 IO 線程和 SQL 線程相差的時間,而後根據該參數值判斷,這個值只是初步判斷,不能由這個值來下結論,有以下幾種狀況:
a、0:表示無延遲,理想狀態;
b、NULL:表示從庫上的 IO 線程和 SQL 線程中,有某一個線程出現問題,能夠再次查看 Slave_IO_Running 和 Slave_SQL_Running 的值是否都爲 Yes;
c、大於 0:表示主從已經出現延遲,這個值越大,表示從庫和主庫之間的延遲越嚴重;
d、小於 0:這個值在官方文檔中沒有說明,一般不會出現。若是出現,那恭喜你中獎了,撞見 MySQL 的 bug 了;
(2)根據主從庫上面當前應用的二進制日誌文件名稱或者重放日誌的位置來判斷
① 同時打開兩個 MySQL 的命令行窗口,分別打開主庫和從庫,在第一個窗口上執行查看主庫當前狀態的命令
mysql-server-3306> SHOW MASTER STATUS G
*** 1. row ***
File: mysql-bin.000017
Position: 120
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set:
1 row in set (0.00 sec)
② 在第二個從庫的命令行窗口執行以下命令
mysql-server-3307> SHOW SLAVE STATUS G
*** 1. row ***
Slave_IO_State: Waiting for master to send event
…
Connect_Retry: 60
Master_Log_File: mysql-bin.000017
Read_Master_Log_Pos: 120
Relay_Log_File: relay-log.000016
Relay_Log_Pos: 283
Relay_Master_Log_File: mysql-bin.000017
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
…
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 120
Relay_Log_Space: 613
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
…
Seconds_Behind_Master: 0
…
Replicate_Ignore_Server_Ids:
Master_Server_Id: 3
Master_UUID: 2dbbf79b-5d9f-11e8-8004-000c29e28409
Master_Info_File: /mysql_data/3307/data/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
③ 比較從庫上的 Master_Log_File 和 Relay_Master_Log_File 文件之間是否有差別
a、若是有差別,則說明主從延遲很嚴重;
b、若是沒有差別,則比較 Read_Master_Log_Pos 和 Exec_Master_Log_Pos 的差別,這倆參數分別表示從庫當前讀取到的主庫的二進制日誌文件位置點和已經執行到的位置點;
c、若是上述輸出都沒有差別,能夠經過主庫上」show master status」和從庫上」show slave status」的結果做比較。主要比較主庫的」File」和從庫的」Master_Log_File」,主庫上的」Position」和從庫上的」Read_Master_Log_Pos」;
三、主從延遲解決辦法
(1)判斷是否因爲網絡致使
方法:測試主從庫之間的網絡延遲,好比測試 ping 延遲。同時能夠檢查主從同步的時候是否使用了主庫的域名來同步,而域名解析速度可能會特別慢。或者使用其餘測試工具;
(2)判斷是否因爲硬件環境致使
方法:確認主從庫的硬件配置是否相差較大,若是配置參數相差較大,能夠排查從庫上的 CPU,內存,IO 使用率來判斷是否由於硬件配置致使;
(3)判斷是否在主庫上有大量的 DML 操做
方法:能夠再主庫上經過」show full processlist」命令查看當前正在執行的 sql,查看是否有大量正在執行的 SQL,或者觀察主庫的 CPU 和內存使用率,判斷是否有高併發操做;
(4)判斷是否有慢 SQl,能夠再主庫上臨時打開慢 SQL 記錄,臨時打開方法以下
# 開啓慢 SQL 功能並查看是否生效
mysql-server-3306> SET @@GLOBAL.slow_query_log = ON;
mysql-server-3306> SHOW VARIABLES LIKE ‘slow_query_log’;
# 設置慢 SQL 的時間並查看是否生效,單位爲 s,表示大於多少秒的 SQL 會被記錄
mysql-server-3306> SET @@GLOBAL.long_query_time = 5;
mysql-server-3306> SHOW VARIABLES LIKE ‘long_query_time’;
# 設置慢 SQL 記錄日誌路徑並查看是否生效。注意,這個目錄必須對 MySQL 用戶有讀寫權限
mysql-server-3306> SET @@GLOBAL.slow_query_log_file = ‘/mysql_data/mysql-slow.log’;
mysql-server-3306> SHOW VARIABLES LIKE ‘slow_query_log_file’;
(5)檢查從服務器參數配置是否合理
① 查看從庫是否開啓了 binlog 日誌,從庫上執行以下命令查看
mysql-server-3307> SHOW VARIABLES LIKE ‘log_bin’;
若是開啓了 binlog 日誌,並且從庫未充當其餘庫的主庫時,能夠將從庫上的 binlog 關閉,不然會增長從庫負擔,每次重放完成主庫的 binlog 還要記錄到自身的 binlog
② 查看從庫上的 sync_binlog 參數的值,這個參數表示的是事務提交多少次以後,由 MySQL 來將 binlog_cache 中的數據刷新到磁盤,有如下幾種值:
0:表示事務提交以後,MySQL 不作刷新 binlog_cache 到磁盤的操做,而是由操做系統來定時自動完成刷盤操做,這種操做對性能損耗最少,可是也最不安全;
n:表示提交 n 次事務以後,由 MySQL 將 binlog_cache 中的數據刷新到磁盤,若是開啓,會對性能有必定程度的損耗。因此,從庫上若是延遲很嚴重,能夠考慮將該參數的值設爲 0;
mysql-server-3307> SET @@GLOBAL.sync_binlog = 0;
mysql-server-3307> SHOW VARIABLES LIKE ‘sync_binlog’;
+—————+——-+
| Variable_name | Value |
+—————+——-+
| sync_binlog | 0 |
+—————+——-+
1 row in set (0.00 sec)
③ 若是從庫中要同步的數據庫使用的是 InnoDB 存儲引擎,能夠查看 innodb_flush_log_at_trx_commit 參數。這個參數表示事務執行完成以後,多久的頻率刷新一第二天志到磁盤上,可用的值有以下幾種:
0:表示 MySQL 會將日誌緩衝區中的數據每秒一次地寫入日誌文件中,而且日誌文件的刷盤操做同時進行。該模式下在事務提交的時候,不會主動觸發寫入磁盤的操做,效率最搞,可是安全性也比較低,可能會丟失數據;
1:每一次事務提交都須要把日誌寫入磁盤,這個過程是特別耗時的操做;
2:每一次事務提交以後,不會自動觸發日誌刷盤的操做,而是由操做系統來決定何時來作刷新日誌的操做,在操做系統掛了的狀況下才會丟失數據;
若是在主從延遲很是嚴重的狀況下,能夠將從庫的該參數設置爲 0,以提升從庫上重放主庫二進制日誌的效率。
mysql-server-3307> SET @@GLOBAL.innodb_flush_log_at_trx_commit = 0;
mysql-server-3307> SHOW VARIABLES LIKE ‘innodb_flush_log_at_trx_commit’;
+——————————–+——-+
| Variable_name | Value |
+——————————–+——-+
| innodb_flush_log_at_trx_commit | 0 |
+——————————–+——-+
1 row in set (0.00 sec)
注意:上述設計到修改 MySQL 數據庫實例的操做中,修改以後會馬上生效,可是重啓實例以後,會失效,若是要永久修改,則須要編輯 mysql 配置文件,而後重啓。
至此,主從複製延遲的常見緣由就介紹完畢,還有更多其餘緣由須要實際問題實際解決,此處並未提到
第 11 章 MySQL 數據庫運維之數據備份 01
上篇文章介紹了 MySQL 主從複製中常見問題排查。在主從複製架構搭建完成以後,須要按期對數據進行備份,本篇文章開始就來介紹 MySQL 數據庫的數據備份與恢復,因爲備份及恢復內容較多,分多個小節介紹,本小節先來介紹 MySQL 數據庫備份的相關概念及 mysqldump 邏輯備份工具。
一、備份類型
(1)按照備份後的文件來劃分
a、物理備份:直接備份數據庫文件,經常使用的有 LVM 邏輯卷備份,或者直接拷貝壓縮數據庫數據目錄
b、邏輯備份:使用備份工具將數據庫中的數據導出爲數據庫 sql 腳本或者數據文件
(2)按照是否中止數據庫服務劃分
a、冷備:備份期間須要中止數據庫服務,會形成不可讀不可寫
b、溫備:備份期間不須要中止數據庫服務,可是須要鎖表,故只能讀,不可寫
c、熱備:備份期間,數據庫服務徹底不受影響,可讀可寫
(3)按照備份的週期和備分內容劃分
a、徹底備份:一次性備份數據庫實例中的全部數據
b、增量備份:若是剛進行過一次徹底備份,則增量備份就指的是全備以後到當前時間點之間增長的數據;
若是上次爲增量備份,則增量備份指的內容是上次增量以後到當前時間點之間增長的數據
c、差別備份:僅備份上次全量備份以後發生變化的數據,因爲比增量備份耗費的磁盤空間更多,故用的比較少
二、備份策略
(1)全量備份 + 增量備份
(2)全量備份 + 差別備份
三、備份工具介紹
(1)mysqldump:基於 MySQL 客戶端的一個邏輯備份工具,可實現溫備,能夠使用 -u,-p,-h 等選項備份遠程數據庫上的數據
(2)mysqlhotcopy:基於 MySQL 客戶端的一個物理工具,只可冷備,備份過程當中需指定 -u,-p,-h,-S 等基本參數,這些基本參數的含義和 mysql 命令對應的參數含義相同
(3)lvm2:基於 lvm 的物理備份工具,因爲是經過對邏輯卷作快照來實現的,因此備份速度極快,可在瞬間完成,可粗略認爲是熱備
(4)xtrabackup:Percona 旗下的一塊開源 MySQL 備份工具,能夠實如今線熱備和溫備
除此以外還有一些其餘備份工具,如 mysqldumper,PhpMyAdmin 等,感興趣可本身查資料學習。
四、mysqldump 邏輯備份基本操做
(1)用法
mysqldump [OPTIONS] database [tables]
OR mysqldump [OPTIONS] –databases [OPTIONS] DB1 [DB2 DB3…]
OR mysqldump [OPTIONS] –all-databases [OPTIONS]
(2)經常使用參數選項 OPTIONS
-A,–all-databases:該選項表示備份實例中的全部數據庫
-B,–databases:指定要備份的數據庫名稱,後面能夠同時跟多個數據庫
-E,–events:表示備份過程當中包括數據庫中的事件
-F,–flush-logs:表示備份完成以後刷新日誌,滾動日誌點,若是沒有開啓二進制日誌,使用該選項會提示錯誤
–flush-privileges:表示備份最新的權限表數據
–hex-blob:表示備份過程當中包括數據庫中的二進制數據(BINARY,VARBINARY,BLOG)
-x,–lock-all-tables:該選項的做用是在備份過程當中鎖定全部的表,一般用於備份 MyISAM 存儲引擎類型的表數據
–single-transaction:該選項表示備份過程當中保證數據的一致性,使用事務隔離狀態和一致性快照保證,目前只支持 InnoDB 類型的表
注:–lock-all-tables 選項和–single-transaction 選項同時只能用一個
–master-data=N:該選項用來設置在導出的數據中是否包括對二進制日誌文件和日誌點的記錄,經常使用的值有:1 和 2
1:表示在導出的 sql 文件中包括了」change master to master_log_file=’’,master_log_pos=N」內容,用來作快速主從複製
2:表示在導出的 sql 文件中不包括」change master to master_log_file=’’,master_log_pos=N」內容
-t,–no-create-info:表示只備份數據,不備份表的建立信息
-d,–no-data:表示只備份表結構,不備份任何數據
-R,–routines:表示備份中同時備份存儲過程和函數
–tables:若是不須要備份整個庫,只須要備份部分表,能夠使用該選項指定
–triggers:表示備份中同時備份觸發器
-u:指定完成備份操做的用戶名
-p:指定完成備份操做的用戶密碼
-h:指定完成備份操做的域名或者 ip 地址
-P:指定完成備份操做的端口號。注意,是大寫的 P
(3)示例
示例 1:完成 127.0.0.1 服務器上 3306 數據庫實例的全量備份
[root@WB-BLOG ~]# mkdir -pv /backup/
[root@WB-BLOG ~]# mysqldump -uroot -proot -h127.0.0.1 -P3306 -S /tmp/mysql.sock –all-databases –routines –triggers –single-transaction –events –master-data=2 | gzip > /backup/full_db_date +%F
.sql.gz
# 檢查文件是否正常,這步很很很重要。有時候因爲一些緣由,備份文件生成了,可是打不開,因此務必檢查
[root@WB-BLOG ~]# gzip -d /backup/full_db_2018-06-18.sql.gz
[root@WB-BLOG ~]# less /backup/full_db_2018-06-18.sql
示例 2:使用 root 用戶備份 127.0.0.1 服務器上 3306 實例中的 test 庫,並完成壓縮放在 /backup 目錄下
[root@WB-BLOG ~]# mysqldump -uroot -proot -h127.0.0.1 -P3306 -S /tmp/mysql.sock –databases test –routines –triggers –single-transaction –events –master-data=2 | gzip > /backup/test-date +%F
.sql.gz
[root@WB-BLOG ~]# ls /backup/test-2018-06-18.sql.gz
# 查看是否備份成功
[root@WB-BLOG ~]# gzip -d /backup/test-2018-06-18.sql.gz
[root@WB-BLOG ~]# less /backup/test-2018-06-18.sql
示例 3:備份 127.0.0.1 服務器上 3306 實例中的 test 庫中的 user 表
[root@WB-BLOG ~]# mysqldump -uroot -proot -h127.0.0.1 -P3306 -S /tmp/mysql.sock –databases test –tables user –routines –triggers –master-data=2 –events| gzip > /backup/Db-test_Tb-user_date +%F
.sql.gz
[root@WB-BLOG ~]# ls /backup/Db-test_Tb-user_2018-06-18.sql.gz
# 查看是否備份成功
[root@WB-BLOG ~]# gzip -d /backup/Db-test_Tb-user_2018-06-18.sql.gz
[root@WB-BLOG ~]# less /backup/Db-test_Tb-user_2018-06-18.sql
示例 4:備份 127.0.0.1 服務器上 3306 實例中的 mysql 庫的表結構,不備份數據
[root@WB-BLOG ~]# mysqldump -uroot -proot -h127.0.0.1 -S /tmp/mysql.sock -P3306 –databases mysql –no-data –triggers –routines –master-data=2 –events| gzip > /backup/mysql_table_frame_date +%F
.sql.gz
# 查看是否備份成功
[root@WB-BLOG ~]# gzip -d /backup/mysql_table_frame_2018-06-18.sql.gz
[root@WB-BLOG ~]# less /backup/mysql_table_frame_2018-06-18.sql
示例 5:備份 127.0.0.1 服務器上 3306 實例中的 test 庫中全部表的數據,不備份表結構
[root@WB-BLOG ~]# mysqldump -uroot -proot -h127.0.0.1 -S /tmp/mysql.sock -P3306 –databases test –no-create-info –triggers –routines –master-data=2 –events| gzip > /backup/test_table_data_date +%F
.sql.gz
# 查看是否備份成功
[root@WB-BLOG ~]# gzip -d /backup/test_table_data_2018-06-18.sql.gz
[root@WB-BLOG ~]# less /backup/test_table_data_2018-06-18.sql
實例 6:在 windows 上遠程備份 192.168.0.10 服務器上的 3306 數據庫實例中的 mysql 數據庫
前提:須要在 0.10 服務器上授予 windows 主機的遠程鏈接權限,受權操做可查看以前文章,此處略
D:SoftWaremysql-5.7.21bin>mysqldump -uroot -proot -h127.0.0.1 -P3306 –databases mysql > D:/remote_mysql.sql
# 查看 D 盤根目錄,發現已經備份完成,查看備份文件也正常
至此,第一小節 MySQL 備份相關概念及 mysqldump 邏輯備份工具介紹完畢,下一篇文章將繼續介紹 MySQL 的物理備份工具 Xtrabackup
第 12 章 MySQL 數據庫運維之數據備份 02
上篇文章介紹了一下 MySQL 數據庫邏輯備份第一部分 mysqldump 的使用,本篇文章將繼續介紹 MySQL 數據庫邏輯備份第二部分 Xtrabackup 工具的操做過程!
一、Xtrabackup 介紹
Xtrabackup 是有 Percona 公司發行的一款數據庫物理備份工具,能夠對 InnoDB 存儲引擎的表實如今線熱備,同時能夠對數據庫進行全備和增量備份以及增量恢復。
二、下載及安裝
(1)下載地址:https://www.percona.com/downl... ,根據自身的操做系統選擇版本,版本若是不對應,會安裝失敗,本人使用的是 CentOS6.9_X64 的操做系統,下載的版本爲:percona-xtrabackup-24-2.4.8-1.el6.x86_64.rpm
(2)安裝依賴庫 perl-DBD-MySQL,若是已經安裝,直接進入下一步
# 查看是否安裝
[root@WB-BLOG ~]# rpm -qa | grep perl-DBD-MySQL
# 若是沒有安裝,使用下面的命令安裝 perl-DBD-MySQL
[root@WB-BLOG ~]# yum install -y per-DBD-MySQL
(3)安裝 libev 依賴庫
a、下載地址:在 http://rpmfind.net/ 直接搜索 libev,而後選擇和本身操做系統對應的 rpm 安裝包
b、注意:此處也須要注意版本,不然會安裝失敗,本人用的是 CentOS6.9_X64 的操做系統,下載的 rpm 安裝包版本爲:libev-4.04-2.el6.x86_64.rpm
c、安裝:
[root@WB-BLOG ~]# rpm -ivh libev-4.04-2.el6.x86_64.rpm
(4)安裝 perl-Digest-MD5 依賴庫,不然在備份過程當中會出現錯誤
[root@WB-BLOG ~]# yum -y install perl-Digest-MD5
(5)安裝 Xtrabackup
[root@WB-BLOG ~]# rpm -ivh percona-xtrabackup-24-2.4.8-1.el6.x86_64.rpm
三、使用方法
語法:innobackupex [OPTIONS] /path
經常使用參數 OPTIONS 說明:
—————————————基本備份參數———————————
–user:指定執行備份操做的用戶名
–password:指定執行備份操做的用戶密碼
–host:指定數據庫所在服務器的域名或者 IP 地址
–port:指定實例端口
–socket:指定 socket 文件,以便備份進程登錄 mysql
–databases:指定要備份的數據庫,若是須要備份多個數據庫,多個數據庫之間使用空格隔開,如:–databases=」test1 test2」
–include:指定要備份的數據庫,能夠指定多個庫」db1.|db2.「
還能夠指定要備份的表,能夠指定多個表」db1.table01|db1.table02|db2.test」
–defaults-file:指定數據庫實例的配置文件 my.cnf。注:若是用該參數,必須放在第一個參數位置,不然會提示錯誤
–apply-log:經過回滾未提交的事務及同步已經提交的事務至數據文件來保證數據文件處於一致性狀態
–redo-only:用來保證全備和增量備份的數據文件在恢復前必須先將在重作日誌文件中的已提交的事務重作,該參數將會合並全備和增量備份的數據文件,但不包括最後一次增量備份的數據文件
–copy-back:指定操做爲數據的恢復,若是不是全備,不可用這個選項,這個選項用於全備的恢復
–slave-info:在主從庫備份中使用,用來備份從庫的」show slave status」信息
–stream:指定備份文件的輸入格式,如:tar
–tmpdir:若是使用 stream=tar 的時候備份,xtrabackup_logfile 可能會放在臨時目錄 /tmp 下,若是此時數據庫中數據寫入量特別大的時候,這個文件會特別大,可能會將 /tmp 目錄佔滿,使用這個參數能夠指定 tmp 目錄
–no-timestamp:該選項後面不用加值,用來指定備份的時候不適用默認的日期目錄,而是使用指定好的目錄
—————————————增量備份參數———————————
–incremental:指定操做爲增量備份操做
–incremental-basedir:指定本次的增量備份是相對於以前的哪一次備份,指定以前備份數據的目錄
–incremental-dir:指定增量備份恢復時,增量備份的目錄
其餘更多參數,能夠使用」innobackupex –help」命令查看。
四、備份及恢復示例
示例 1:全量備份 127.0.0.1 上 3306 實例中的全部數據,備份到 /backup 目錄下,而後模擬數據丟失恢復
備份:
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –user=root –password=root –port=3306 –socket=/tmp/mysql.sock /backup/
# 上述命令執行完成以後,打印 completed ok. 而後查看是否備份成功,很重要
[root@WB-BLOG ~]# ls /backup/
恢復:
# 模擬故障,刪除數據目錄
[root@WB-BLOG ~]# rm -rf /mnt/mydata/data/*
# 殺掉 mysql 的服務進程
[root@WB-BLOG ~]# killall mysqld
# 應用 log 日誌,目的是爲了回滾未提交的事務及同步已經提交的事務至數據目錄,保證數據的一致性
[root@WB-BLOG ~]# innobackupex –apply-log /backup/2018-05-29_10-27-53/
# 恢復數據,指定配置文件,xtrabackup 會將數據文件拷貝到原來的數據目錄中
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –copy-back /backup/2018-05-29_10-27-53/
# 拷貝完成以後,權限會有問題,須要從新受權
[root@WB-BLOG ~]# chown -R mysql:mysql /mnt/mydata/data/
# 從新啓動數據庫來驗證是否恢復正常
[root@WB-BLOG ~]# service mysqld start
示例 2:全量備份 127.0.0.1 服務器上 3306 實例的全部數據,並備份到目錄 /backup/20180619 目錄下,而後恢復
備份:
[root@WB-BLOG ~]# mkdir -pv /backup/20180619
[root@WB-BLOG ~]# innobackupex –user=root –password=root –host=127.0.0.1 –port=3306 –socket=/tmp/mysql.sock –no-timestamp /backup/20180619/
[root@WB-BLOG ~]# ls /backup/20180619/
恢復,處理過程和示例 1 相同,再也不解釋:
[root@WB-BLOG ~]# rm -rf /mnt/mydata/data/*
[root@WB-BLOG ~]# killall mysqld
[root@WB-BLOG ~]# innobackupex –apply-log /backup/20180619/
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –copy-back /backup/20180619/
[root@WB-BLOG ~]# chown -R mysql:mysql /mnt/mydata/data/
[root@WB-BLOG ~]# service mysqld start
示例 3:備份 127.0.0.1 服務器上 3306 實例中的 test1 和 test2 數據庫,並備份到 /backup/part_db/ 目錄下,而後恢復
備份:
[root@WB-BLOG ~]# mkdir -pv /backup/part_db
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –user=root –password=root –host=127.0.0.1 –port=3306 –socket=/tmp/mysql.sock –databases=」test1 test2」 –no-timestamp /backup/part_db/
[root@WB-BLOG ~]# ls /backup/part_db/
恢復:
# 模擬數據庫丟失
[root@WB-BLOG ~]# mysql -uroot -proot -h127.0.0.1 -P3306 -e 「drop database test1」
[root@WB-BLOG ~]# mysql -uroot -proot -h127.0.0.1 -P3306 -e 「drop database test2」
# 應用 log 日誌,使未提交的事務回滾,已經提交的數據同步到數據目錄中
[root@WB-BLOG ~]# innobackupex –apply-log /backup/part_db/
# 因爲是部分數據庫的恢復,因此不能使用–copy-back 選項,因此須要使用拷貝的方法
[root@WB-BLOG ~]# cp -r /backup/part_db/test{1,2}/ /mnt/mydata/data/
# 受權
[root@WB-BLOG ~]# chown -R mysql:mysql /mnt/mydata/data/test{1,2}
# 重啓數據庫
[root@WB-BLOG ~]# servie mysqld restart
示例 4:增量備份 127.0.0.1 服務器上 3306 實例中的全部庫,第一次增量備份到目錄 /backup/increment01,第二次增量備份到目錄 /backup/increment02,全量備份到 /backup/allback 而後恢復
備份:
# 建立全量備份和增量備份目錄
[root@WB-BLOG ~]# mkdir -pv /backup/allback
[root@WB-BLOG ~]# mkdir -pv /backup/increment{01,02}
# 完成一次全量備份
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –user=root –password=root –host=127.0.0.1 –port=3306 –socket=/tmp/mysql.sock –no-timestamp /backup/allback/
# 完成第一次增量備份,此時可能會有新數據寫入
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –user=root –password=root –host=127.0.0.1 –port=3306 –socket=/tmp/mysql.sock –no-timestamp –incremental-basedir=/backup/allback/ –incremental /backup/increment01/
# 完成第二次全量備份,此時可能會有新數據寫入
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –user=root –password=root –host=127.0.0.1 –port=3306 –socket=/tmp/mysql.sock –no-timestamp –incremental-basedir=/backup/increment01/ –incremental /backup/increment02/
# 查看兩次備份的數據目錄是否正常
[root@WB-BLOG ~]# ls /backup/increment0{1,2}
恢復:
# 模擬數據丟失
[root@WB-BLOG ~]# rm -rf /mnt/mydata/data/*
[root@WB-BLOG ~]# killall mysqld
# 完成全備的 log 日誌應用
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –incremental –apply-log –redo-only /backup/allback/
# 完成第一次增量中 log 日誌的應用
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –incremental –apply-log –redo-only /backup/allback/ –incremental-dir=/backup/increment01/
# 完成第二次增量中 log 日誌的應用
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –incremental –apply-log –redo-only /backup/allback/ –incremental-dir=/backup/increment02/
# 兩次增量都合併到全量中以後,再應用全量中的 log 日誌
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –apply-log /backup/allback/
# 最後全量恢復全備文件夾中的數據
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –copy-back /backup/allback/
# 從新受權
[root@WB-BLOG ~]# chown -R mysql:mysql /mnt/mydata/data/
# 而後啓動數據庫服務,而後驗證數據是否正確
[root@WB-BLOG ~]# service mysqld start
示例 5:壓縮備份 127.0.0.1 服務器上的 3306 實例中的 test1 庫到 /backup/test1_data,而後恢復
備份:
# 建立備份目錄
[root@WB-BLOG ~]# mkdir -pv /backup/test1_data
# 壓縮備份
[root@WB-BLOG ~]# innobackupex –defaults-file=/etc/my.cnf –user=root –password=root –host=127.0.0.1 –port=3306 –socket=/tmp/mysql.sock –compress –no-timestamp –databases=」test1」 /backup/test1_data/
恢復:
# 模擬刪掉數據庫 test1
[root@WB-BLOG ~]# mysql -uroot -proot -h127.0.0.1 -P3306 -e 「drop database test1」
# 恢復,首先解壓縮
[root@WB-BLOG ~]# innobackupex –decompress /backup/test1_data/
# 注意:若是提示以下錯誤,則須要安裝 qpress 工具,下載地址:ftp://ftp.pbone.net/mirror/ftp5.gwdg.de/pub/opensuse/repositories/home:/AndreasStieger:/branches:/Archiving/CentOS_CentOS-6/x86_64/qpress-1.1-8.3.x86_64.rpm,使用 rpm 命令安裝
innobackupex version 2.4.8 based on MySQL server 5.7.13 Linux (x86_64) (revision id: 97330f7)
180529 12:29:01 [01] decompressing ./ibdata1.qp
sh: qpress: command not found
cat: write error: Broken pipe
Error: thread 0 failed.
[root@WB-BLOG ~]# innobackupex –apply-log /backup/test1_data
# 拷貝備份數據
[root@WB-BLOG ~]# cp -r /backup/test1_data/test1/ /mnt/mydata/data/
[root@WB-BLOG ~]# chown -R mysql:mysql /mnt/mydata/data/test1/
# 重啓數據庫而後驗證數據是否正確
[root@WB-BLOG ~]# service mysqld restart
至此,Xtrabackup 物理備份工具介紹完畢,常見的用法能夠參考上述的示例。另外,該工具還有其餘高級用法,使用較少,此處暫未介紹。
第 13 章 MySQL 數據庫運維之數據備份 03
上篇文章介紹了一下 MySQL 的數據備份與恢復第二部份內容,即便用 Xtrabackup 完成 MySQL 數據庫的物理備份與恢復,可是 Xtrabackup 主要是針對於 InnoDB 表引擎格式的備份,其餘存儲引擎並不適用。本篇文章將介紹使用 LVM 完成 MySQL 的數據備份和恢復!
1、LVM 簡單介紹
一、定義
LVM,全稱爲:Logical Volume Manager。意思是邏輯卷管理,是 Linux 環境下對磁盤分區進行管理的一種機制。早期的磁盤分區在分完區以後沒法改變分區的大小,可是一般使用磁盤以前又不能對須要的磁盤容量進行準確評估,可能會形成磁盤不夠用或者磁盤浪費等問題,而 LVM 能夠動態建立和修改磁盤大小,能夠有效地解決這個問題。
二、重要概念
(1)PV(Physical Volume):表示物理卷,在邏輯卷管理系統最底層,可爲整個物理硬盤或實際物理硬盤上的分區;
(2)VG(Volume Group):表示卷組,創建在物理捲上,一個卷組中至少要包括一個物理卷,卷組創建後可動態的添加捲到卷組中,一個邏輯卷管理系統工程中可有多個卷組;
(3)LV(Logical Volume):邏輯卷創建在卷組基礎上,卷組中未分配空間可用於創建新的邏輯卷,邏輯卷創建後能夠動態擴展和縮小空間;
(4)PE(Physical Extent):物理區域是物理卷中可用於分配的最小存儲單元,物理區域大小在創建卷組時指定,一旦肯定不能更改,同一卷組全部物理卷的物理區域大小需一致,新的 PV 加入到 VG 後,PE 的大小自動更改成 VG 中定義的 PE 大小;
(5)LE(Logical Extent):邏輯區域是邏輯卷中可用於分配的最小存儲單元,邏輯區域的大小取決於邏輯卷所在卷組中的物理區域的大小;
更多內容能夠參考工具書《鳥哥的 Linux 私房菜》,裏面有詳細介紹。
三、各部分組成結構
2、建立邏輯卷並備份
一、備份前提
(1)待備份的 MySQL 數據必須在在邏輯捲上
(2)若是是 InnoDB 存儲引擎表,爲了保證備份以後的數據一致性,須要事務日誌和數據都在同一個捲上,由於同一時刻只能對一個邏輯卷作快照
二、備份過程
(1)首先須要準備一塊磁盤或者一個分區,此處演示使用 VMware 新加磁盤的辦法,首先關閉 Vmware,具體操做過程以下
到此,磁盤添加完畢,啓動 Vmware 虛擬機。
(2)使用以下命令查看新添加的磁盤
[root@WB-BLOG ~]# fdisk -l
(3)使用剛纔添加的磁盤來建立物理卷
[root@WB-BLOG ~]# pvcreate /dev/sdb
Physical volume 「/dev/sdb」 successfully created
# 查看建立的物理卷
[root@WB-BLOG ~]# pvdisplay
「/dev/sdb」 is a new physical volume of 「10.00 GiB」
— NEW Physical volume —
PV Name /dev/sdb
…
(4)根據物理捲來建立卷組
[root@WB-BLOG ~]# vgcreate mygroup /dev/sdb
Volume group 「mygroup」 successfully created
參數解釋:
mygroup:表示卷組的名稱
/dev/sdb:表示使用哪一個物理捲來建立卷組
# 查看建立的卷組
[root@WB-BLOG ~]# vgdisplay
— Volume group —
VG Name mygroup
…
(5)根據上一步建立的卷組來建立邏輯卷
[root@WB-BLOG ~]# lvcreate -n mysqldata –size 3G mygroup
Logical volume 「mysqldata」 created.
參數解釋:
-n:表示要建立的邏輯卷的名稱
–size:表示要建立的邏輯卷的大小
mygroup:表示使用哪一個卷組來建立邏輯卷
# 查看建立的邏輯卷
[root@WB-BLOG ~]# lvdisplay
— Logical volume —
LV Path /dev/mygroup/mysqldata
LV Name mysqldata
VG Name mygroup
LV UUID qHJyK4-eMUF-gQku-ojkC-j7Tr-hayA-UFsq5J
(6)格式化剛纔建立的邏輯卷,建立完邏輯卷以後,邏輯卷的默認磁盤路徑爲 /dev/ 卷組名稱 / 邏輯卷名稱,經過 lvdisplay 命令輸出結果中的」LV Path」也能夠看到
[root@WB-BLOG ~]# mkfs.ext4 /dev/mygroup/mysqldata
(7)掛載邏輯捲到一個目錄上
# 使用 blkid 查看設備的 UUID 編號
[root@WB-BLOG ~]# blkid /dev/mygroup/mysqldata
/dev/mygroup/mysqldata: UUID=」46483472-1c46-4af5-8844-d39fd653d57d」 TYPE=」ext4」
# 上述輸出的 UUID 爲設備的 UUID 號,能夠使用該 ID 編號將這個邏輯卷掛載到某個目錄上
[root@WB-BLOG ~]# mkdir -pv /mnt/
[root@WB-BLOG ~]# vim /etc/fstab
# 在末尾加入以下一行,表示將 UUID 爲 4648…的邏輯卷設備掛載到 /mnt 目錄,而後保存退出
UUID=」46483472-1c46-4af5-8844-d39fd653d57d」 /mnt ext4 defaults 0 0
# 讓操做系統讀取 fstab 文件內容,並重新執行掛載
[root@WB-BLOG ~]# mount -a
# 查看邏輯卷是否掛載成功,看到以下一行表示掛載成功
[root@WB-BLOG ~]# df -h
/dev/mapper/mygroup-mysqldata 2.9G 4.5M 2.8G 1% /mnt
(8)在 /mnt 目錄下建立 MySQL 的數據目錄 data
[root@WB-BLOG ~]# mkdir -pv /mnt/mydata/data/
(9)修改 MySQL 配置文件和啓動腳本中的 datadir 目錄和 binlog 日誌路徑到 data 目錄下
[root@WB-BLOG ~]# vim /etc/my.cnf
# 修改以下內容
datadir = /mnt/mydata/data
log_bin = /mnt/mydata/data/mysql-bin
binlog_format = mixed
log_bin_index = /mnt/mydata/data/mysql-bin-index
…
[root@WB-BLOG ~]# vim /etc/init.d/mysqld
# 修改以下內容
datadir=/mnt/mydata/data
…
(10)受權,並從新初始化 MySQL 數據庫到 /mnt/mydata/data 目錄下
[root@WB-BLOG ~]# chown -R mysql:mysql /mnt/mydata/data/
[root@WB-BLOG ~]# cd /usr/local/mysql-5.6.39/scripts/
[root@WB-BLOG scripts]# ./mysql_install_db –user=mysql –group=mysql –datadir=/mnt/mydata/data/ –basedir=/usr/local/mysql-5.6.39
(11)啓動數據庫,查看是否正常
[root@WB-BLOG scripts]# service mysqld start
至此,MySQL 的數據目錄已經在 LVM 邏輯捲上。
(12)假如實例已經使用了一段時間,新的數據已經在 LVM 邏輯卷中了,如今須要備份。則能夠經過建立邏輯卷快照完成 MySQL 的數據備份
[root@WB-BLOG scripts]# lvcreate –snapshot /dev/mygroup/mysqldata -n data-snap –size 1G –permission r
Logical volume 「data-snap」 created.
# 以上命令表示使用 /dev/mygroup/mysqldata 邏輯卷建立了一個名稱爲 data-snap 大小爲 1G 的只讀快照
參數解釋:
–snapshot:表示建立邏輯卷快照
-n:指定快照名稱
–size:指定快照的大小
–permission:指定快照對使用者的操做權限,上述權限爲只讀
# 查看是否備份成功,須要將這個快照卷掛載到某個目錄上查看
[root@WB-BLOG scripts]# mount /dev/mygroup/mysqldata /tmp/
[root@WB-BLOG scripts]# ls /tmp/mydata/data/
(13)備份完成以後,能夠將備份的數據打包壓縮,而後移除邏輯卷快照
# 打包數據
[root@WB-BLOG scripts]# tar zcvf mysql_data_date +%F
.tar.gz /tmp/mydata/data/
# 移除邏輯卷快照,能夠使用 lvdisplay 命令查看到剛纔建立的邏輯卷快照的名稱
[root@WB-BLOG scripts]# lvremove /dev/mygroup/data-snap
Do you really want to remove active logical volume data-snap? [y/n]: y
Logical volume 「data-snap」 successfully removed
(14)數據恢復,使用剛纔打包的備份文件完成數據的恢復
# 模擬數據丟失(刪庫!注意千萬不要正式環境嘗試…)
[root@WB-BLOG scripts]# rm -rf /mnt/mydata/data/*
# 中止 mysqld 進程
[root@WB-BLOG scripts]# killall mysqld
[root@WB-BLOG scripts]# tar xf mysql_data_2018-05-30.tar.gz
# 移動數據並受權
[root@WB-BLOG scripts]# mv tmp/mydata/data/* /mnt/mydata/data/
[root@WB-BLOG scripts]# chown -R mysql:mysql /mnt/mydata/data/
# 啓動數據庫
[root@WB-BLOG scripts]# service mysqld start
(15)登陸以後檢查數據是否還原
至此,基於 LVM 的 MySQL 數據備份與恢復介紹完畢,下片文章開始將結合 MySQL 的二進制日誌介紹數據的全量和增量恢復
來源連接:https://segmentfault.com/u/xiarihanbing/articles
第 14 章 關於 MySQL 的知識點與面試常見問題
14.1 書籍推薦
《高性能 MySQL : 第 3 版》
14.2 文字教程推薦
MySQL 教程(菜鳥教程)
MySQL 教程(易百教程)
14.3 視頻教程推薦
基礎入門: 與 MySQL 的零距離接觸 - 慕課網
Mysql 開發技巧: MySQL 開發技巧(一) MySQL 開發技巧(二) MySQL 開發技巧(三)
Mysql5.7 新特性及相關優化技巧: MySQL5.7 版本新特性 性能優化之 MySQL 優化
MySQL 集羣(PXC)入門 MyCAT 入門及應用
14.4 常見問題總結
• ①存儲引擎
MySQL 常見的兩種存儲引擎:MyISAM 與 InnoDB 的愛恨情仇
• ②字符集及校對規則
字符集指的是一種從二進制編碼到某類字符符號的映射。校對規則則是指某種字符集下的排序規則。Mysql 中每一種字符集都會對應一系列的校對規則。
Mysql 採用的是相似繼承的方式指定字符集的默認值,每一個數據庫以及每張數據表都有本身的默認值,他們逐層繼承。好比:某個庫中全部表的默認字符集將是該數據庫所指定的字符集(這些表在沒有指定字符集的狀況下,纔會採用默認字符集) PS:整理自《Java 工程師修煉之道》
詳細內容能夠參考: MySQL 字符集及校對規則的理解
• ③索引相關的內容(數據庫使用中很是關鍵的技術,合理正確的使用索引能夠大大提升數據庫的查詢性能)
Mysql 索引使用的數據結構主要有 BTree 索引 和 哈希索引 。對於哈希索引來講,底層的數據結構就是哈希表,所以在絕大多數需求爲單條記錄查詢的時候,能夠選擇哈希索引,查詢性能最快;其他大部分場景,建議選擇 BTree 索引。
Mysql 的 BTree 索引使用的是 B 數中的 B+Tree,但對於主要的兩種存儲引擎的實現方式是不一樣的。
MyISAM: B+Tree 葉節點的 data 域存放的是數據記錄的地址。在索引檢索的時候,首先按照 B+Tree 搜索算法搜索索引,若是指定的 Key 存在,則取出其 data 域的值,而後以 data 域的值爲地址讀取相應的數據記錄。這被稱爲「非聚簇索引」。
InnoDB: 其數據文件自己就是索引文件。相比 MyISAM,索引文件和數據文件是分離的,其表數據文件自己就是按 B+Tree 組織的一個索引結構,樹的葉節點 data 域保存了完整的數據記錄。這個索引的 key 是數據表的主鍵,所以 InnoDB 表數據文件自己就是主索引。這被稱爲「聚簇索引(或彙集索引)」。而其他的索引都做爲輔助索引,輔助索引的 data 域存儲相應記錄主鍵的值而不是地址,這也是和 MyISAM 不一樣的地方。在根據主索引搜索時,直接找到 key 所在的節點便可取出數據;在根據輔助索引查找時,則須要先取出主鍵的值,在走一遍主索引。 所以,在設計表的時候,不建議使用過長的字段做爲主鍵,也不建議使用非單調的字段做爲主鍵,這樣會形成主索引頻繁分裂。 PS:整理自《Java 工程師修煉之道》
詳細內容能夠參考:
乾貨:mysql 索引的數據結構
MySQL 優化系列(三)–索引的使用、原理和設計優化
• ④查詢緩存的使用
my.cnf 加入如下配置,重啓 Mysql 開啓查詢緩存
query_cache_type=1
query_cache_size=600000
Mysql 執行如下命令也能夠開啓查詢緩存
set global query_cache_type=1;
set global query_cache_size=600000;
如上,開啓查詢緩存後在一樣的查詢條件以及數據狀況下,會直接在緩存中返回結果。這裏的查詢條件包括查詢自己、當前要查詢的數據庫、客戶端協議版本號等一些可能影響結果的信息。所以任何兩個查詢在任何字符上的不一樣都會致使緩存不命中。此外,若是查詢中包含任何用戶自定義函數、存儲函數、用戶變量、臨時表、Mysql 庫中的系統表,其查詢結果也不會被緩存。
緩存創建以後,Mysql 的查詢緩存系統會跟蹤查詢中涉及的每張表,若是這些表(數據或結構)發生變化,那麼和這張表相關的全部緩存數據都將失效。
緩存雖然可以提高數據庫的查詢性能,可是緩存同時也帶來了額外的開銷,每次查詢後都要作一次緩存操做,失效後還要銷燬。 所以,開啓緩存查詢要謹慎,尤爲對於寫密集的應用來講更是如此。若是開啓,要注意合理控制緩存空間大小,通常來講其大小設置爲幾十 MB 比較合適。此外,還能夠經過 sql_cache 和 sql_no_cache 來控制某個查詢語句是否須要緩存:
select sql_no_cache count(*) from usr;
• ⑤事務機制
關係性數據庫須要遵循 ACID 規則,具體內容以下:
垂直拆分的優勢: 能夠使得行數據變小,在查詢時減小讀取的 Block 數,減小 I/O 次數。此外,垂直分區能夠簡化表的結構,易於維護。
垂直拆分的缺點: 主鍵會出現冗餘,須要管理冗餘列,並會引發 Join 操做,能夠經過在應用層進行 Join 來解決。此外,垂直分區會讓事務變得更加複雜;
水平拆分能夠支持很是大的數據量。須要注意的一點是: 分表僅僅是解決了單一表數據過大的問題,但因爲表的數據仍是在同一臺機器上,其實對於提高 MySQL 併發能力沒有什麼意義,因此 水品拆分最好分庫 。水平拆分可以 支持很是大的數據量存儲,應用端改造也少,但 分片事務難以解決 ,跨界點 Join 性能較差,邏輯複雜。《Java 工程師修煉之道》的做者推薦 儘可能不要對數據進行分片,由於拆分會帶來邏輯、部署、運維的各類複雜度 ,通常的數據表在優化得當的狀況下支撐千萬如下的數據量是沒有太大問題的。若是實在要分片,儘可能選擇客戶端分片架構,這樣能夠減小一次和中間件的網絡 I/O。下面補充一下數據庫分片的兩種常見方案: 客戶端代理: 分片邏輯在應用端,封裝在 jar 包中,經過修改或者封裝 JDBC 層來實現。 噹噹網的 Sharding-JDBC 、阿里的 TDDL 是兩種比較經常使用的實現。 中間件代理: 在應用和數據中間加了一個代理層。分片邏輯統一維護在中間件服務中。 咱們如今談的 Mycat 、360 的 Atlas、網易的 DDB 等等都是這種架構的實現。詳細內容能夠參考:MySQL 大表優化方案