1.1.爲何選擇MySQL
MySQL有什麼特色?
一、能夠處理擁有上千萬條記錄的中小型數據
二、使用標準的SQL數據語言形式
三、可移植行高,安裝簡單小巧
四、調試、管理,優化簡單(相對其餘大型數據庫)
五、開源(分爲商業版和社區版)
html
2.1.MySQL概述
1.MySQL是一個關係型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品,是最流行的關係型數據庫管理系統之一。
2.MySQL是一種關係數據庫管理系統,關係數據庫就是將數據保存在不一樣的表中,而不是將全部數據放在一個大倉庫內,這樣就增長了數據的訪問速度和靈活性。
3.MySQL 軟件採用了雙受權政策,分爲社區版和商業版,因爲其體積小、速度快、整體擁有成本低,尤爲是開放源碼這一特色,通常中小型網站的開發都選擇 MySQL 做爲網站數據庫,因爲其社區版的性能卓越,搭配 PHP 和 Apache 可組成良好的開發環境。
2.2.MySQL的安裝配置
2.2.1.MySQL的安裝
2.2.1.1.linux安裝方法一mysql
1.配置 yum 源 去 MySQL 官網下載 YUM 的 RPM 安裝包,http://dev.mysql.com/downloads/repo/yum/ 下載 mysql 源安裝包: $ curl -LO wget https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm 安裝 mysql 源 $ sudo yum localinstall mysql80-community-release-el7-3.noarch.rpm 檢查 yum 源是否安裝成功 $ sudo yum repolist enabled | grep "mysql.*-community.*" mysql-connectors-community MySQL Connectors Community 21 mysql-tools-community MySQL Tools Community 38 mysql80-community MySQL 5.7 Community Server 130 2.安裝 $ sudo yum install mysql-community-server 3.啓動 安裝服務 $ sudo systemctl enable mysqld 啓動服務 $ sudo systemctl start mysqld 查看服務狀態 $ sudo systemctl status mysqld 4.修改 root 默認密碼 MySQL 5.7 啓動後,在 /var/log/mysqld.log 文件中給 root 生成了一個默認密碼。經過下面的方式找到 root 默認密碼,而後登陸 mysql 進行修改: $ grep 'temporary password' /var/log/mysqld.log [Note] A temporary password is generated for root@localhost: ********** 登陸 MySQL 並修改密碼上面找出的密碼 $ mysql -u root -p Enter password: 修改密碼,IDENTIFIED BY 中輸入新的密碼 mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass4!'; 注意:MySQL 5.7 默認安裝了密碼安全檢查插件(validate_password),默認密碼檢查策略要求密碼必須包含:大小寫字母、數字和特殊符號,而且長度不能少於 8 位。 經過 MySQL 環境變量能夠查看密碼策略的相關信息: mysql> SHOW VARIABLES LIKE 'validate_password%'; +--------------------------------------+--------+ | Variable_name | Value | +--------------------------------------+--------+ | validate_password_check_user_name | OFF | | validate_password_dictionary_file | | | validate_password_length | 8 | | validate_password_mixed_case_count | 1 | | validate_password_number_count | 1 | | validate_password_policy | MEDIUM | | validate_password_special_char_count | 1 | +--------------------------------------+--------+ 7 rows in set (0.01 sec) $ sudo vi /etc/my.cnf [mysqld] # 指定密碼校驗策略,這樣咱們就能夠將密碼不用按:大小寫字母、數字和特殊符號,而且長度不能少於 8 位的方式設置複雜的密碼了 # 添加以下鍵值對, 0=LOW, 1=MEDIUM, 2=STRONG validate_password_policy=0 [mysqld] 重啓 MySQL 服務,使配置生效 $ sudo systemctl restart mysqld 5.添加遠程登陸用戶 MySQL 默認只容許 root 賬戶在本地登陸,若是要在其它機器上鍊接 MySQL,必須修改 root 容許遠程鏈接,或者添加一個容許遠程鏈接的賬戶,爲了安全起見,本例添加一個新的賬戶admin,密碼爲:secret: mysql> GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%' IDENTIFIED BY 'secret' WITH GRANT OPTION; 6.配置默認編碼爲 utf8,MySQL 默認爲 latin1, 通常修改成 UTF-8 $ vi /etc/my.cnf [mysqld] # 在myslqd下添加以下鍵值對 character_set_server=utf8 init_connect='SET NAMES utf8' 重啓 MySQL 服務,使配置生效 $ sudo systemctl restart mysqld 查看字符集 mysql> SHOW VARIABLES LIKE 'character%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 8 rows in set (0.00 sec) 7.開啓端口 $ sudo firewall-cmd --zone=public --add-port=3306/tcp --permanent $ sudo firewall-cmd --reload
2.2.1.2.linux安裝方法二linux
1.安裝前咱們須要先去官網下載 Yum 資源包,下載地址爲: https://dev.mysql.com/downloads/repo/yum/ 我使用的是centos7,因此使用第一個: wget https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm 2.rpm -ivh mysql80-community-release-el7-3.noarch.rpm 3.yum update輸入Y後進行下載 4.yum install mysql-server輸入Y進行下載 權限設置: chown mysql:mysql -R /var/lib/mysql 初始化 MySQL: mysqld --initialize 啓動 MySQL: systemctl start mysqld 查看 MySQL 運行狀態: systemctl status mysqld 配置的方式如同方式一,這裏再也不作講解
2.2.1.3.linux安裝方法三程序員
1系統約定 安裝文件下載目錄:/data/software Mysql目錄安裝位置:/usr/local/mysql 數據庫保存位置:/data/mysql 日誌保存位置:/data/log/mysql 2下載mysql 在官網:http://dev.mysql.com/downloads/mysql/ 中,選擇如下版本的mysql下載: 執行以下命名: #mkdir -p /data/software #cd /data/software 下載安裝包: #wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.17-linux-glibc2.5-x86_64.tar.gz 或者在主機上下載了,與虛擬機進行共享,virtual box虛擬機與主機進行文件共享具體的方法參考: 3解壓壓縮包到目標位置 #cd /data/software --解壓壓縮包 #tar -xzvf /data/software/mysql-5.7.17-linux-glibc2.5-x86_64.tar.gz --移動並修改文件名 #mv /data/software/mysql-5.7.17-linux-glibc2.5-x86_64 /usr/local/mysql 4建立數據倉庫目錄 --/data/mysql 數據倉庫目錄 # mkdir /data/mysql #ls /data/ 5新建mysql用戶、組及目錄 # ---新建一個msyql組 # useradd -r -s /sbin/nologin -g mysql mysql -d /usr/local/mysql ---新建msyql用戶禁止登陸shell 6改變目錄屬有者 #cd /usr/local/mysql #pwd #chown -R mysql . #chgrp -R mysql . #chown -R mysql /data/mysql 7配置參數 # bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql 此處須要注意記錄生成的臨時密碼,如上文結尾處的:YLi>7ecpe;YP #bin/mysql_ssl_rsa_setup --datadir=/data/mysql 8修改系統配置文件 #cd /usr/local/mysql/support-files # cp my-default.cnf /etc/my.cnf 【這一個實際操做中沒有用到,由於我上面/usr/local/mysql/support-files文件下沒有my-default.cnf文件】 # cp mysql.server /etc/init.d/mysql # vim /etc/init.d/mysql 修改如下內容: 9啓動mysql # /etc/init.d/mysql start --登錄 # mysql -hlocalhost -uroot -p --若是出現:-bash: mysql: command not found --就執行: # ln -s /usr/local/mysql/bin/mysql /usr/bin --沒有出現就不用執行 --輸入第6步生成的臨時密碼 --修改密碼 mysql> set password=password(‘123456’); --須要注意的是,新版的MySQL不支持password函數,因此須要使用這兩種方式: alter user 'root'@'localhost' identified by '123456'; 或 set password for 'root'@'localhost'=password('123456'); --設置root帳戶的host地址(修改了才能夠遠程鏈接) mysql>grant all privileges on *.* to 'root'@'%' identified by ‘123456’; mysql>flush privileges; --查看錶 mysql> use mysql; mysql> select host,user from user; 10添加系統路徑 # vim /etc/profile 添加: export PATH=/usr/local/mysql/bin:$PATH 以下: # source /etc/profile 11配置mysql自動啓動 # chmod 755 /etc/init.d/mysql # chkconfig --add mysql # chkconfig --level 345 mysql on 這樣咱們就能夠直接使用mysql -uroot -p的方式登陸了
2.2.1.4.Windows安裝方法一:MySQL的安裝包安裝web
以安裝包的方式安裝更像是一種傻瓜式的安裝方式,因此咱們能夠不用再額外的進行環境變量的配置和MySQL的配置,只要咱們在安裝過程當中勾選相應的選項,MySQL會自動幫咱們進行基本的配置。正則表達式
1.輸入https://www.mysql.com/downloads/地址進入MySQL官網,點擊Community(GPL) Downloads 2.選擇MySQL on Windows(Installer & Tools)後點擊DOWNLOAD 3.選擇MySQL Installer 4.選擇mysql-installer-community-8.0.11.0.msi後點擊下載。 (這裏mysql-installer-community-8.0.11.0.msi是能夠運行在無網絡的環境下,而mysql-installer-web-community-8.0.11.0.msi只能運行在有網絡的) 5.而後運行下載好的安裝包,一路點擊NEXT便可完成安裝,在開始菜單裏能夠找到MySQL Workbench 6.3 CE,打開可進入mysql。 6.咱們也能夠使用cmd命令提示符打開MySQL,環境變量的配置,默認是安裝在C:\Program Files下的,將C:\Program Files\MySQL\MySQL Server 5.7\bin添加至系統變量Path中後,使用管理員打開cmd,而後開啓MySQL:net start mysql57
2.2.1.5.Windows安裝方法二:MySQL的壓縮包安裝算法
以壓縮包的方式進行安裝,須要本身額外的進行環境變量配置和MySQL的配置 1.輸入https://www.mysql.com/downloads/地址進入MySQL官網,點擊Community(GPL) Downloads 2.根據本身的電腦選擇相應的版本進行下載 3.下載好壓縮包解壓以後,進行環境變量的配置,將文件夾下bin所在的路徑添加至系統變量PATH中。
2.2.2.MySQL的配置
1.在MySQL的根目錄下新建一個my.ini進行文件的配置,配置內容以下:sql
[mysql] # 設置mysql客戶端默認字符集 default-character-set=utf8 [mysqld] #設置mysql服務端默認字符集 character-set-server=utf8 #設置3306端口 port = 3306 # 設置mysql的安裝目錄 basedir=C:\mysql\mysql-5.7.20-winx64 # 設置mysql數據庫的數據的存放目錄 datadir=C:\mysql\mysql-5.7.20-winx64\data # 容許最大鏈接數 max_connections=200 # 建立新表時將使用的默認存儲引擎 default-storage-engine=INNODB
2.MySQL相關目錄的介紹shell
bin目錄:用於存儲一些可執行文件,如mysql.exe、mysqld.exe、mysqlshow.exe等。
data目錄: 用於放置一些日誌文件以及數據庫。
docs 目錄:用於存放一些文檔
include目錄:用於存儲一些頭文件如:mysql.h、mysql_ername.h等。
lib目錄:用於放置一系列庫文件。
share目錄: 用於存放字符集、語言等信息
2.2.3.啓動和關閉MySQL(以管理員的身份進入cmd)數據庫
mysqld --initialize:初始化data目錄 mysqld install MySQL:註冊MySQL服務(mysqld install MySQL --defaults-file = ‘C:\mysql\mysql-5.7.20-winx64\my.ini’’,能夠在註冊MySQL服務時指定默認的配置文件) net start MySQL:啓動MySQL,這裏的mysql是上面註冊的MySQL的服務的名稱,根據本身MySQL的服務名稱進行更換就好了。 net stop MySQL:關閉MySQL 一樣咱們能夠使用:net start 服務名稱 來開啓服務.
2.2.4.MySQL訪問服務器的客戶程序
1.Mysql:一個命令行客戶程序,用於交互式或以批處理模式執行SQL語句。 2.Mysqladmin:用於管理功能的客戶程序。 3.Mysqlcheck:執行表維護操做。 4.mysqldump和mysqlhotcopy:負責數據庫備份。 5.Mysqlimport:導入數據文件。 6.Mysqlshow:顯示信息數據庫和表的相關信息。 7.Myisamchk:執行表維護操做。 8.Myisampack:產生壓縮、只讀的表。 9.Mysqlbinlog:處理二進制日誌文件的實用工具。 10.Perror:顯示錯誤代碼的含義。
2.3.MySQL基本操做
2.3.1.登陸和退出MySQL
在剛安裝好MySQL後,可直接使用mysql -uroot回車後可直接登陸進入MySQL,最開始時咱們的root用戶是沒有密碼的,完整的方式爲:
mysql -uroot -p -P3306 -h127.0.0.1:其中,-u表示用戶,-p表示密碼,注意密碼和-p之間不能有空格,-P表示端口號,-h表示服務器ip,本地的爲127.0.0.1或者localhost
exit或者quit:退出MySQL
注意:由於mysql5.7新增的特性中主要的一方面就是極大加強了安全性,安裝Mysql後默認會爲root@localhost用戶建立一個隨機密碼,因此咱們第一次登陸以後就須要使用set password = password(‘newpassword’)來修改密碼,否則第二次登陸MySQL時,由於是隨機的密碼,咱們就很難找到登陸密碼(目前還不知道在Windows怎麼去找MySQL的隨機密碼,多是看data目錄下的錯誤日誌文件)
2.3.2.MySQL特徵及經常使用命令
2.3.2.1.主要特徵
1.mysql不區分大小寫,但爲了更好的操做數據庫,一般關鍵字和函數均爲大寫,數據庫名稱、表名稱、字段名稱均爲小寫; 2.語句默認以分號結尾,在命令提示符中必需要使用分號來作結束符,固然咱們能夠使用delimiter 來更改結束符,好比delimiter //咱們的結束符就從;變爲了// 3.在查詢的SELECT和WHERE部分支持所有運算符和函數; 4.全面支持SQL的GROUP BY和ORDER BY子句,支持聚合函數( COUNT()、COUNT(DISTINCT)、AVG()、STD()、SUM()、 MAX()和MIN() ); 5.支持ANSI SQL的LEFT OUTER JOIN和ODBC語法; 6.能夠在同一查詢中混用來自不一樣數據庫的表;(select * from t1 where id in (select id from am.teacher)) 7.每一個表容許有16個索引。每一個索引能夠由1~16個列或列的一部分組成。最大索引長度是 256 個字節(在編譯MySQL時,它能夠改變)。一個索引能夠使用一個CHAR或VARCHAR字段的前綴; 8.大數據庫處理。能夠對包含 50,000,000 個記錄的數據庫使用MySQL; 9.全部列都有缺省值,能夠用INSERT插入一個表列的子集,那些沒用明確給定值的列設置爲他們的缺省值; 10.全部數據以 ISO-8859-1 Latin1 格式保存。全部正常的字符串比較是忽略大小寫的; 11.函數名不會與表或列名衝突。例如ABS是一個有效的列名字。對函數調用的惟一限制是函數名與隨後的「(」不能有空格; 12.DELETE、INSERT、REPLACE和UPDATE 返回有多少行被改變(受影響); 13.MySQL特有的SHOW命令可用來檢索數據庫、表和索引的信息,EXPLAIN命令可用來肯定優化器如何解決一個查詢。
2.3.2.2.經常使用命令
1.select version():查看MySQL版本 2.select database():查看當前使用的數據庫 3.select user():查看當前登陸的用戶 4.select now():查看當前時間 5.select @@datadir:查看MySQL數據庫存放目錄 6.select @@basedir:查看MySQL的安裝基礎目錄 7.select @@max_connections:查看MySQL的最大鏈接數 8.show variables like ‘validate_password’:查看密碼策略
2.3.3.操做數據庫
1.查看全部的數據庫:show databases 2.使用數據庫,或者叫打開數據庫:use db_name 3.建立數據庫:create database [if not exists] db_name [[default] character set utf8]; 建立完成後,能夠在MySQL的安裝目錄下的DATA目錄中找到一個名爲「db_name」的文件夾,該文件夾便是用於保存此數據庫信息和數據的文件夾。
實際上,若是手動在該目錄下建立一個名爲「db_name」的目錄,MySQL服務器會將其做爲一個正常的數據庫目錄。 4.查看該數據庫的字符編碼方式:show create database db_name; 5.修改數據庫的編碼方式:alter database db_name [default] character set gbk; 6.刪除數據庫:drop database db_name; 使用普通用戶,你可能須要特定的權限來建立或者刪除 MySQL 數據庫,因此咱們一般使用root用戶登陸,root用戶擁有最高權限。 7.另外咱們能夠使用 mysql 的mysqladmin 命令來建立數據庫。mysqladmin -uroot -p create table_name 實例:mysqladmin -uroot -p create ying 這樣咱們就建立了一個名爲ying的數據庫
2.3.3.1.mysqladmin
介於以上的知識,咱們延伸下mysqladmin的一些基本經常使用知識
mysqladmin 工具的使用格式: mysqladmin [option] command [command option] command ...... 參數選項: -c number 自動運行次數統計,必須和 -i 一塊兒使用 -i number 間隔多長時間重複執行
0)每隔兩秒查看一次服務器的狀態,總共重複5次。 mysqladmin -uroot -p -i 2 -c 5 status
其中
1.Uptime表示:服務器已經運行的時間(以秒爲單位);
2.Threads表示:線程數;Questions表示:已經發送給服務器的查詢的個數;
3.Slow Queries表示:查詢時間超過long_query_time秒的查詢的個數;
4.Flush tables表示:執行的FLUSH語句數。
具體的MySQL show status參數能夠參考:https://www.cnblogs.com/zengkefu/p/5634841.html
1)查看服務器的情況:status mysqladmin -uroot -p status 2)修改root 密碼: mysqladmin -u root -p原密碼 password newpassword 注意-p和原密碼之間不能有空格 以下,將root原密碼111111修改成了123456: mysqladmin -uroot -p111111 password 123456 3)檢查mysqlserver是否可用: mysqladmin -uroot -p ping 若是MySQL服務正常啓動的,那麼將會顯示以下內容: 若是MySQL服務未正常啓動的,則會顯示以下內容: 4)查詢服務器的版本 mysqladmin -uroot -p version 5)查看服務器狀態的當前值: mysqladmin -uroot -p extended-status 6)查詢服務器系統變量值: mysqladmin -uroot -p variables 7)顯示數據庫服務器全部運行的進程: mysqladmin -uroot -p processlist mysqladmin -uroot -p-i 1 processlist //每秒刷新一次 8)建立數據庫 mysqladmin -uroot -p create database_name 9)顯示服務器上的全部數據庫 mysqlshow -uroot -p 10)顯示數據庫database_name下有些什麼表: mysqlshow -uroot -p database_name 11)統計database_name 下數據庫表列的彙總 mysqlshow -uroot -p database_name -v 12)統計database_name 下數據庫表的列數和行數 mysqlshow -uroot -p database_name -v -v 13)刪除數據庫 database_name mysqladmin -uroot -p drop database_name 14)重載權限信息 mysqladmin -uroot -p reload 15)刷新全部表緩存,並關閉和打開log mysqladmin -uroot -p refresh 16)使用安全模式關閉數據庫 mysqladmin -uroot -p shutdown
2.3.3.2.修改密碼
在修改密碼前,咱們先來了解下MySQL的密碼策略,使用以下命令能夠查看現有的密碼策略: mysql> show variables like 'validate_password%'; +--------------------------------------+--------+ | Variable_name | Value | +--------------------------------------+--------+ | validate_password_check_user_name | OFF | | validate_password_dictionary_file | | | validate_password_length | 8 | | validate_password_mixed_case_count | 1 | | validate_password_number_count | 1 | | validate_password_policy | MEDIUM | | validate_password_special_char_count | 1 | +--------------------------------------+--------+ 7 rows in set (0.01 sec) 1.validate_password_number_count參數是密碼中至少含有的數字個數,當密碼策略是MEDIUM或以上時生效。 2.validate_password_special_char_count參數是密碼中非英文數字等特殊字符的個數,當密碼策略是MEDIUM或以上時生效。 3.validate_password_mixed_case_count參數是密碼中英文字符大小寫的個數,當密碼策略是MEDIUM或以上時生效。 4.validate_password_length參數是密碼的長度。 5.validate_password_dictionary_file參數是指定密碼驗證的字典文件路徑,只有當策略爲2時才使用獲得 6.validate_password_policy這個參數能夠設爲 0=LOW, 1=MEDIUM, 2=STRONG,分別表明從低到高的密碼強度,此參數的默認值爲1,若是想將密碼強度改弱,則更改此參數爲0。 因此,若是咱們修改的密碼不符合密碼策略設置的規則時,修改密碼時就會報錯,若是隻僅僅是考慮方便,這時咱們也能夠經過修改密碼策略來處理。 mysql> set global validate_password_policy=0; mysql> set global validate_password_length=4; 下面開始修改密碼: 最簡單的方法就是藉助第三方工具Navicat for MySQL來修改,方法以下: 1、登陸mysql到指定庫,如登陸到xiong庫,而後點擊上方「用戶」按鈕。 3、選擇要更改的用戶名,而後點擊上方的「編輯用戶」按鈕。 4、出現如圖界面,輸入新密碼,並確認新密碼,點擊「保存」按鈕便可。
第二種方式: 方法1: 用set password命令 若是咱們使用root用戶登陸的話,就能夠使用該方式修改全部用戶的密碼,若是咱們使用普通的用戶登陸的話,就只能修改本身的密碼。 首先登陸MySQL:mysql -uroot -p 格式:mysql> set password for 用戶名@localhost = password('新密碼'); 例子1:mysql> set password for root@localhost = password('123'); 例子2:mysql>set password for test@localhost = password(‘123456’) 方法2:用mysqladmin 格式:mysqladmin -u用戶名 -p舊密碼 password 新密碼 例子1:mysqladmin -uroot -p123456 password 123 例子2:mysqladmin -utest -p123456 password 11111 方法3:用UPDATE直接編輯user表 對於MySQL5.7之前的版本使用以下 首先登陸MySQL:mysql -uroot -p mysql> use mysql; mysql> update user set password=password('123') where user='root' and host='localhost'; mysql> flush privileges; 對於MySQL5.7及之後的版本,MYSQL的用戶表的密碼字段變了,再也不是password字段,而是authentication_string字段。 mysql> use mysql; mysql> update user set authentication_string=password('密碼') where user='root' and Host = 'localhost' mysql> flush privileges; 方法4:使用alter alter user ‘username’@’hostname’ identified by ‘newpwd’ alter user 'test'@'localhost' identified by '123456';
3.數據類型與數據操做
3.1.MySQL數據類型
數據類型是指列、存儲過程參數、表達式和局部變量的數據特徵,它決定了數據的存儲格式,表明了不一樣的信息類型。
3.1.1.整型
tinyint 【1個字節,有符號:-2^7—2^7-1 無符號:0—2^8-1】 smallint 【2個字節,有符號:-2^15—2^15-1 無符號:0—2^16-1】 mediumint 【3個字節】 int 【4個字節】 bigint 【 8個字節】 注意: 1.UNSIGNED 修飾符規定字段只保存正值。由於不須要保存數字的正、負符號,能夠在儲時節約一個「位」的空間。從而增大這個字段能夠存儲的值的範圍,須要注意的是若是沒有明確的添加UNSIGNED修飾符,默認就是有符號位的。 2.ZEROFILL 修飾符規定 0(不是空格)能夠用來填補(從左邊填補)輸出的值。使用這個修飾符能夠阻止 MySQL 數據庫存儲負值。 3.MySQL 以一個可選的顯示寬度指示器的形式對 SQL 標準進行擴展,這樣當從數據庫檢索一個值時,能夠把這個值加長到指定的長度。例如,指定一個字段的類型爲 INT(6),就能夠保證所包含數字少於 6 個的值從數據庫中檢索出來時可以默認自動地用空格填充。須要注意的是,使用一個寬度指示器不會影響字段的大小和它能夠存儲的值的範圍。
3.1.2.浮點型
FLOAT float[D,M] 其中D表示精度總數字位數(精度),M表示小數的位數(標度),D和M可選的,其中D的範圍:1~65,M的範圍:0~30 1.不指定D,M時,只能存6個數字(包括小數點先後的位數) 2.只指定D時,只能存6個數字(包括小數點先後的位數) 3.若指定D,M時,先知足小數位M,而後再看整數位,整數位不能大於D-M,輸入的值好比float(5,2),規定了存儲的值不會超過 5 位數字,而且小數點後不超過 2 位,由於小數位有2位了,因此整數部分就只能輸入3位的 4.D<=24時,類型爲float,若53>D>24則爲double類型的(在沒有標度的狀況下,若是有標度的狀況下仍是float) DOUBLE double[D,M] 其中D表示總數字位數,M表示小數的位數,後面的D和M可選的 1.不指定D,M時,可存儲17位數字(包括小數點先後的位數) 2.在double中,若是指定了D,那麼就要指定M 3.若指定D,M時,先知足小數位M,而後再看整數位,整數位不能大於D-M,輸入的值好比double(5,2),規定了存儲的值不會超過 5 位數字,而且小數點後不超過 2 位,由於小數位有2位了,因此整數部分就只能輸入3位的 4.double的精度爲能夠到53 DECIMAL decimal[D,M] decimal適合於更高精度類型的數值,其中D表示總數字位數,M表示小數的位數,後面的D和M可選的 1. D範圍爲1〜65,M的範圍爲0~30,可存儲38位數字 2.若是沒有指定D,M時,D默認爲10,M默認爲0 3.MySQL使用二進制格式存儲decimal值。它將9位數字包裝成4個字節。對於每一個部分,須要4個字節來存儲9位數的每一個倍數。 例如,DECIMAL(19,9)對於小數部分具備9位數字,對於整數部分具備10位數字,小數部分須要4個字節。 整數部分對於前9位數字須要4個字節,1個剩餘字節須要1個字節。DECIMAL(19,9)列總共須要9個字節。 注意: 1.對於小數點後面的位數超過容許範圍的值,MySQL 會自動將它四捨五入爲最接近它的值,再插入它。 2.UNSIGNED 和 ZEROFILL 修飾符也能夠被 FLOAT、DOUBLE 和 DECIMAL 數據類型使用。而且效果與 INT 數據類型相同。 類型 大小 範圍(有符號) 範圍(無符號) 用途 TINYINT 1 字節 (-128,127) (0,255) 小整數值 SMALLINT 2 字節 (-32 768,32 767) (0,65 535) 大整數值 MEDIUMINT 3 字節 (-8 388 608,8 388 607) (0,16 777 215) 大整數值 INT或INTEGER 4 字節 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整數值 BIGINT 8 字節 (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 極大整數值 FLOAT 4 字節 (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 單精度 浮點數值 DOUBLE 8 字節 (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 雙精度 浮點數值 DECIMAL 對DECIMAL(M,D) ,若是M>D,爲M+2不然爲D+2 依賴於M和D的值 依賴於M和D的值 小
3.1.3.時間日期型
year 【1個字節 1970-2069】 time 【3個字節 -838:59:59~838:59:59】 date 【3個字節 1000.1.1~9999.12.31】 datetime 【8個字節 1000.1.1 00:00:00 ~ 9999.12.31 23:59:59】 timestamp 【時間戳,4個字節 1970.1.1 00:00:00起秒數,若是咱們對 timestamp類型的字段沒有明確賦值,或是被賦與了 null 值。MySQL 會自動使用系統當前的日期和時間來填充它】 類型 大小 (字節) 範圍 格式 用途 DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 日期值 TIME 3 '-838:59:59'/'838:59:59' HH:MM:SS 時間值或持續時間 YEAR 1 1901/2155 YYYY 年份值 DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 混合日期和時間值 TIMESTAMP 4 1970-01-01 00:00:00/2038 結束時間是第 2147483647 秒,北京時間 2038-1-19 11:14:07,格林尼治時間 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和時間值,時間戳
3.1.4.字符型
char(M) 【M個字節,M的範圍爲:0-255,長度不夠的用空格進行填充】 varchar(M) 【<=M個字節,M的範圍爲:0-65535】 MySQL 提供了 TEXT 和 BLOB 兩種類型。根據存儲數據的大小,它們都有不一樣的子類型。這些大型的數據用於存儲文本塊或圖像、聲音文件等二進制數據類型。 文本數據 【不區分大小寫,會忽略尾部空格,tinytext,text,mediumtext,longtext】 二進制文本數據 【會區分大小寫,tinyblob,blob,mediumblob,longblob】 enum :枚舉 1.單選字符串數據類型,適合存儲表單界面中的「單選值」。 2.設定enum的時候,須要給定「固定的幾個選項」;存儲的時候就只存儲其中的一個值。 enum("選項1","選項2","選項3",...); 3.實際上,enum的選項都會對應一個數字,依次是1,2,3,4,5...,最多有65535個選項,1-255爲一個字節,256-65535爲第二個字節。 4.使用的時候,能夠使用選項的字符串格式,也能夠使用對應的數字。 eg:定義時:gender enum('M','F') 插入時:能夠value (''M」)或者value(1) set : 1.多選字符串數據類型,適合存儲表單界面的「多選值」,當存儲多個相同的值,最終只保留一個。 2.設定set的時候,一樣須要給定「固定的幾個選項」;存儲的時候,能夠存儲其中的若干個值。 3.設定set的格式:set("選項1","選項2","選項3",...) 4.一樣的,set的每一個選項值也對應一個數字,依次是1,2,4,8,16...,最多有64個選項,每8位一個字節 5.使用的時候,能夠使用set選項的字符串自己(多個選項用逗號分隔),也能夠使用多個選項的數字之和(好比:1+2+4=7) 定義時:hobby set('music','movie','swimming','footbal') 插入時:能夠value('music','movie')等同於value(3) 類型 大小 用途 CHAR 0-255字節 定長字符串 VARCHAR 0-65535 字節 變長字符串 TINYBLOB 0-255字節 不超過 255 個字符的二進制字符串 TINYTEXT 0-255字節 短文本字符串 BLOB 0-65 535字節 二進制形式的長文本數據 TEXT 0-65 535字節 長文本數據 MEDIUMBLOB 0-16 777 215字節 二進制形式的中等長度文本數據 MEDIUMTEXT 0-16 777 215字節 中等長度文本數據 LONGBLOB 0-4 294 967 295字節 二進制形式的極大文本數據 LONGTEXT 0-4 294 967 295字節 極大文本數據
3.1.5.位類型
bit[位數] 1.此類型用於聲明一個指定位數的數據,位數的取值範圍是1到64,默認值是1。此類型所佔用的字節數由「位數」決定,每滿8位即需一個新的字節,其長度的計算方法爲「(位數+7)/8」,若有小數則進一。如BIT[25]佔用4個字節,而BIT[26]則佔用5個字節。 2.此數據類型用於存儲基於位的數值,指定位類型的值時,能夠採用b‘二進制值’的寫法。如, b'111' 表明7,b'10000000'表明128。 3.若是所插入的值的位數比指定的位數少時,MySQL會在值的左邊用0填充,如將值b’111’插入到BIT[8]時,等同於插入值b’00000111’。 bool型 1.bool型數據用於存儲邏輯值,它只有兩種狀態,即「TRUE」和「FALSE」,或「1」和「0」。此類型等價於TINYINT(1)類型。其值爲0時表示「FALSE」,全部非0值都表示「TRUE」。
3.2.MySQL操做數據表
3.2.1.數據庫經常使用註釋符 # 但在pg數據庫中不行 如:SELECT * FROM `test1` where number=2 #and age=24 -- (注意:--後面有一個空格) 如:SELECT * FROM `test1` where number=2 -- and age=24 /*...*/ 如:SELECT * FROM `test1` where number=2 /*and age=24*/ 另外經常使用的註釋符還有:--+,可是在MySQL中只有上面三種 3.2.2.數據表的增-create 幾個經常使用的命令 1.show tables;(在當前數據庫下,使用這個默認展現當前數據庫下的數據表) 2.等同於:select table_name from information_schema.tables where table_schema=database() 3.show tables from db_name(使用該方法可查看任何某一個數據庫下的數據表) 4.select database(); (查看當前正在使用的數據庫) 5.desc tb_name或者show columns from tb_name或者show fields from tb_name(查看錶的結構) 建立表的模式 create table [if not exists] tb_name (col_name1 data_type constraint,col_name2 data_type constraint); 約束 1.約束分爲表級約束和列級約束,對一個數據列創建的約束叫列級約束,其中not null和default約束就只有列級約束,列級約束既能夠在列定義時聲明,也能夠在列定義後聲明。對兩個及以上的數據列創建的約束叫表級約束,表級約束只能在列定義後聲明。 2.空值和非空:null,not null 3.主鍵約束:primary key 一個表中只能有一個主鍵,主鍵默認爲not null,主鍵建立後會自動建立索引 4.惟一約束:unique key 惟一約束的值爲惟一的,可是與primary key的區別就是,unique key能夠爲null,null的值是能夠重複的。惟一約束和主鍵約束建立後會自動建立索引,可經過show index from tb_name來查看錶中建立的索引 5.外鍵約束:foreign key,有外鍵的表叫子表,子表參照的表叫作父表,外鍵使用時須要注意的幾點: 1.父表和子表必須使用相同的存儲引擎,並且禁止使用臨時表; 2.數據表的存儲引擎只能爲InnoDB 3.外鍵列和參照列必須具備類似的數據類型,其中數字的長度或是否有符號位必須相同;而字符的長度則能夠不一樣 4.外鍵列和參照列必須建立索引.若是外鍵列不存在索引的話,MySQL將自動建立索引. 實例以下: create table test( id tinyint unsigned primary key ); create table test1( id tinyint unsigned, name varchar(20) not null, foreign key(id) references test(id) )engine=myisam,charset=utf8 6.默認約束:default 通常若是未指定not null 那麼未寫默認值時該字段的默認只爲NULL。默認值必須爲常數,不能是函數或表達式,例如,一個日期列的默認值不能被設置爲一個函數,如NOW()或CURRENT_DATE。這裏有一個特例,能夠對TIMESTAMP列指定CURRENT_TIMESTAMP爲默認值。BLOB和TEXT類型的列不能指定默認值。 7.其餘約束: 1)自動編號:auto_increment時必須是primary key且是整數類型的,可是反過來就不必定;若是對自增列插入了default、NULL或者0,那麼也會自增。通常狀況下序列的開始值爲1,若是須要特定的值,咱們能夠使用:alter tabel tb_name auto_increment = 100 2)或者在建立表的時候指定: create table tb_name( id tinyint unsigned primary key auto_increment, name varchar(20) not null )engine = mysiam auto_increment = 100 3)非負:unsigned 規定字段只保存正值。由於不須要保存數字的正、負符號,能夠在儲時節約一個「位」的空間。從而增大這個字段能夠存儲的值的範圍。 4)補零:zerofill 規定 0(不是空格)能夠用來真補輸出的值。使用這個修飾符能夠阻止 MySQL 數據庫存儲負值 8.各約束的順序: 字段名>dataType>unsigned>zerofill> create table index( id tinyint unsigned zerofill primary key auto_increment not null ); 或者: create table index( id tinyint zerofill unsigned primary key auto_increment not null ); 9.建立臨時表 在建立表格時,能夠使用TEMPORARY關鍵詞使當前創建的表爲臨時表。臨時表只能在當前鏈接中使用,當鏈接關閉時,臨時表也被自動刪除。這意味着兩個不一樣的鏈接能夠建立兩個名稱相同的臨時表,這兩個臨時表不會互相沖突,也不與原有的同名的非臨時表衝突。 若是臨時表的名稱與數據庫中現有的非臨時表名稱相同,則非臨時表會被隱藏,直到該臨時表被刪除爲止。 建立臨時表要求當前賬戶擁有CREATE TEMPORARY TABLES權限。 create temporary table tb_name( id tinyint not null, name char(20) not null ); 10.註釋 1)添加列的註釋 直接在字段的定義後添加comment ‘comment_content’ 2)添加表的註釋 直接在表的定義後添加comment=’comment_content’ 整體以下: CREATE TABLE `xiong123` ( `id` int(11) NOT NULL COMMENT '自增id', `name` varchar(20) DEFAULT NULL COMMENT '姓名', `age` int(11) DEFAULT NULL COMMENT '年齡', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='這是一個表的註釋' 3.2.3.數據表的改-alter 1.添加或刪除列 1)添加單列 alter table tb_name add [column] col_name data_type constraint [first] / [after another_col_name] 實例: alter table test add name varchar(20) not null first 表示添加一個name列,並放在最前面 alter table test add age smallint not null after id 表示添加一個age列,並放在id列的後面一列 建立單列時能夠指定該列的位置 2)添加多列 alter table tb_name add [column] (col_name1 data_type constraint,col_name2......,col_name3......) 建立多列時就不能指定列的位置了 實例: alter table test add (name varchar(20) not null ,age smallint not null) 表示同時添加name,age列 3)刪除列 alter table tb_name drop [column] col_name ,drop [column] col_name2; 實例: alter table test drop name,drop age; 2.添加約束 添加主鍵約束:alter table tb_name add [constraint 約束名] primary key(col_name); 實例: alter table test add primary key(id) 添加惟一約束:alter table tb_name add [constraint 約束名] unique key(col_name1,col_name2); 實例: alter table test add unqiue key(id,name) 添加外鍵約束:alter table tb_name add [constraint 約束名] foreign key(col_name1) references tb_name2(col_name2); 實例: alter table test add foreign key(id) references test1(id) 添加默認約束:alter table tb_name alter [column] col_name set default value; 實例: alter table test alter gender set default ‘M’ 設置test表中gender列的默認值爲M 【默認值約束須要注意的幾點】: 1.默認值必須爲常數,不能是函數或表達式,例如,一個日期列的默認值不能被設置爲一個函數,如NOW()或CURRENT_DATE。 2.這裏有一個特例,能夠對TIMESTAMP列指定CURRENT_TIMESTAMP爲默認值。 3.BLOB和TEXT類型的列不能指定默認值 3.刪除約束 刪除主鍵約束:alter table tb_name drop primary key(由於主鍵就只有一個,因此直接刪除primary key) 實例: alter table test drop primary key 刪除惟一約束:alter table tb_name drop index/key index_name(經過show index form tb_name查看index_name) 實例: alter table test drop index number 表示刪除test表中惟一約束(名字爲number) 刪除默認約束:alter table tb_name alter [column] col_name drop default; 實例: alter table test alter gender drop default 刪除外鍵約束:alter table tb_name drop foreign key 外鍵約束名(show create table tb_name能夠查看外鍵約束名稱) 實例: alter table test drop foreign key test1_ibfk_1 表示刪除test表的外鍵,(經過show create table test來查看test表的外鍵) 4.修改列定義和改名 修改列定義:alter table tb_name modify [column] col_name constraintl [first / after another_col_name](在更改列定義時,若是是primary key列,更改時就不須要再把primary key加上了,否則會顯示主鍵重複的錯誤) 實例: alter table test modify age int unsigned not null 修改age列的定義 修改列名稱:alter table tb_name change [column] col_name1 new_col_name1 constraint [first / after another_col_name],change [column] col_name2 new_col_name2 constraint 修改多個列時,每一個change逗號隔開,change除了修改列定義外,還能夠修改列的名稱(必需要給出新的名稱) 實例: alter table test change age nianling int not null 將age列名改成nianling,記住必定要有後面的dataype和constraint 修改表名稱:alter table tb_name1 rename to/as tb_name2;(修改單個表名稱) rename table tb_name1 to tb_name2,tb_name3 to tb_name4;(修改多個表名稱) 實例: alter table test renam to test2 或者 alter table test rename as test2 rename tabel test to test2,test1 to test3 3.2.4.數據表的刪-drop 刪除表:drop table tb_name 3.2.5.表數據的查詢-select 全部語句的擺放順序: select col_name... from tb_name [where where_condition] 查詢條件 [group by {col_name|position} [asc|desc] 按某個字段進行分組,相同的只顯示第一個 [having where_condition] 分組時,給出顯示條件 [order by {col_name|expr|position} [asc|desc] 排序 [limit{[offset,]row_count|row_count OFFSET offset}] 限制返回數量 查詢時咱們能夠使用as來使用別名,實際上as是能夠省略的,可是這樣很容易致使分歧,因此建議使用別名時都要寫上as,同時別名就能夠使用在order by和group by中。 3.2.5.1.查詢不重複項distinct select distinct 字段1,字段2 from 表名; 實例: select distinct name from test1 表示查詢test1表中name不相同的記錄 select distinct gender,age from test1 表示查詢gender和age同時不一樣的記錄 注意: distinct必須放在最開頭 distinct去重多個字段時,含義是:幾個字段同時重複時纔會被過濾。 3.2.5.2.where語句 表示查詢條件,where語句中能夠使用函數和表達式 實例: select * from test1 where name like ‘%xiong%’ 表示查詢test1表中,name包含xiong的記錄 注意: where後面的條件能夠用>、<、>=、<=、!=(<>)等多種比較運算符,like,not like等,多個條件之間能夠用or、and、not等邏輯運算符 咱們能夠使用like進行模糊查詢,一樣咱們也能夠使用正則表達式來進行查詢 實例: select * from test1 where name REGEXP ‘cai’ 表示查詢name包含cai的記錄 select * from test1 where name REGEXP ‘ying$’ 表示查詢name以ying結尾的記錄 select * from test1 where name REGEXP ‘^xiong’ 表示查詢name以xiong開頭的記錄 3.2.5.3.group by語句 按某個字段進行分組,相同的只顯示第一個,asc爲默認值,表示升序,desc爲降序 實例: select nianling,avg(number) from test1 group by nianling having avg(number)>5; 表示按nianling分組,並過濾掉number平均值大於5的記錄 注意: group by語句一般與聚合函數一塊兒使用,包括sum(求和)、count(*)(記錄數)、max(最大值)、min(最小值) group by若是有多個條件,同時對多個字段進行分組,若是多個字段都相同時顯示一條記錄 3.2.5.4.having語句 用於分組時,給出顯示條件,使用having時的字段必須是前面的查詢展現的列,或者是使用聚合函數(count(),avg(),max()等)的字段。 having後面操做的字段必須是前面展現的字段,如上的實例中,就只能操做nianling和avg(number)這兩個字段,操做了其餘的字段均會報錯 3.2.5.5.order by語句 用於對查詢結果進行排序 實例: select * from test order by id desc,addtime asc 表示先按id降序排列,而後再按addtime升序排列 desc 降序排列,asc 升序排列 order by 後面能夠跟多個不一樣的排序字段,每一個排序字段均可以有不一樣的排序順序。 若是排序字段的值同樣,則相同的字段按照第二個排序字段進行排序。 若是隻有一個排序字段,則字段相同的記錄將會無序排列。 3.2.5.6.limit語句 第一種方式:limit number表示從查詢的結果中的第一行開始,選擇number個行;第二種方式:limit (num1,num2)第一個參數表示從第幾行開始,第一行爲0,而後第二個參數表示取幾行,好比limit(3,2)表示從查詢結果中的第四行開始,選擇兩行的結果。 實例: 3.2.6.表數據的插入-insert 3.2.6.1.insert into 插入單條記錄:insert [into] tb_name[(col_name...)] values(val1...) 插入多條記錄:insert [into ] tb_name[(col_name...)] values(val1...),(val2...),(val3....) 實例: insert into test1 values(1,'xiong','M',2,23),(2,'ying','F',3,24),(3,'cai','M',4,25),(4,'liu','M',5,26) 完整的插入四條記錄 insert into test1(name,number,nianling) values('xiongxiong',22,22) 只插入某幾個字段,其餘字段使用默認值或auto_increment的自增 也能夠這樣: insert into test1 values(default, 'yangyang',default,30,40) 表示id使用默認值即自增,gender使用默認值 注意點: 若是全表插入,能夠不用寫字段,插入時每一個字段都要有匹配的值 當表中只有一個字段時,values能夠寫成value 若是是auto_increment的字段,在插入時能夠寫在字段裏,也能夠不寫,若是不寫會自動增長的,可是若是寫了就要給對應的值,否則會報錯,由於主鍵not null。 若是爲not null的字段,那麼必須有值的插入 若是有默認值的,在插入時咱們能夠把值寫爲default,auto_increment寫成默認值時就是自增,沒寫not null的默認值爲null,寫了default的默認值爲建立表時的默認值。 3.2.6.2.Insert set select insert [into] tb_name1 set col_name1 = (select col_name2 from tb_name2)(從中能夠看出set語句一樣能夠使用子查詢) 3.2.6.3.insert into select 將查詢一個表的記錄插到另一個表中 insert into xiong select * from test1; 示例 首先咱們使用複製表的語句複製一個test1表的複製表xiong,而後使用insert into select的方式來插入數據 查看錶xiong的數據 3.2.7.表數據的更新-update update tb_name set colmun1 = value1,column2 = value2 where expression(更新表示若是沒有指定條件,那麼會更新全部的記錄,因此更新是要謹慎) 實例: update test1 set nianling = 30 where name = 'yangyang' 3.2.8.表數據的刪除-delete delete from tb_name where conditions(刪除表數據時若是沒有指定條件,那麼會刪除表中全部的數據,因此刪除時必定要謹慎)
4.子查詢與鏈接
4.1.MySQL鏈接查詢(字段會增長)
鏈接查詢:將多張表(>2)進行記錄的鏈接(按照某個指定的條件進行數據拼接)。
鏈接查詢的意義: 在用戶查看數據的時候,須要顯示的數據來自多張表。
SQL中將鏈接查詢分紅三類: 內鏈接,外鏈接和交叉鏈接。
4.1.1.交叉鏈接
cross join,也叫作笛卡爾積。從一張表中循環取出每一條記錄, 每條記錄都去另一張表進行匹配,匹配必定保留(沒有條件匹配), 而鏈接自己字段就會增長(保留),最終造成的結果共M*N行
4.1.2.內鏈接
[inner] join, 從左表中取出每一條記錄,去右表中與全部的記錄進行匹配, 匹配必須是某個條件在左表中與右表中相同最終纔會保留結果,不然不保留。on表示鏈接條件,若是沒有on條件就是笛卡爾乘積,on能夠使用where來代替,可是這樣效率會比較低
4.1.3.外鏈接
以某張表爲主,取出裏面的全部記錄, 而後每條與另一張表進行鏈接;無論能不能匹配上條件,最終都會保留;能匹配,正確保留; 不能匹配,其餘表的字段都置空NULL。
4.1.3.1.左外鏈接
left [outer] join:以左表爲主,右表未匹配到的字段都爲NULL,即展現左表全部記錄,右表中不符合條件的自斷值都爲null
4.1.3.2.右外鏈接
right [outer] join:以右表爲主,左表未匹配到的字段都爲NULL
4.1.3.3.全外鏈接
全外鏈接還返回左表中不符合鏈接條件單符合查詢條件的數據行,而且還返回右表中不符合鏈接條件單符合查詢條件的數據行。全外鏈接實際是上左外鏈接和右外鏈接的數學合集(去掉重複),即「全外=左外 UNION 右外」,可是在MySQL中不支持全外鏈接。
SQL查詢的基本原理:兩種狀況介紹。
一、單表查詢:根據WHERE條件過濾表中的記錄,造成中間表(這個中間表對用戶是不可見的);而後根據SELECT的選擇列選擇相應的列進行返回最終結果。
二、兩錶鏈接查詢:對兩表求積(笛卡爾積)並用ON條件和鏈接鏈接類型進行過濾造成中間表;而後根據WHERE條件過濾中間表的記錄,並根據SELECT指定的列返回查詢結果。
三、多表鏈接查詢:先對第一個和第二個表按照兩錶鏈接作查詢,而後用查詢結果和第三個表作鏈接查詢,以此類推,直到全部的表都鏈接上爲止,最終造成一箇中間的結果表,而後根據WHERE條件過濾中間表的記錄,並根據SELECT指定的列返回查詢結果。
理解SQL查詢的過程是進行SQL優化的理論依據。
ON後面的條件(ON條件)和WHERE條件的區別:
ON條件:是過濾兩個連接表笛卡爾積造成中間表的約束條件。
WHERE條件:在有ON條件的SELECT語句中是過濾中間表的約束條件。在沒有ON的單表查詢中,是限制物理表或者中間查詢結果返回記錄的約束。在兩表或多表鏈接中是限制鏈接造成最終中間表的返回結果的約束。
從這裏能夠看出,將WHERE條件移入ON後面是不恰當的。推薦的作法是:
ON只進行鏈接操做,WHERE只過濾中間表的記錄。
鏈接查詢是SQL查詢的核心,鏈接查詢的鏈接類型選擇依據實際需求。若是選擇不當,非但不能提升查詢效率,反而會帶來一些邏輯錯誤或者性能低下。下面總結一下兩錶鏈接查詢選擇方式的依據:
一、 查兩表關聯列相等的數據用內鏈接。
二、 Col_L是Col_R的子集時用右外鏈接。
三、 Col_R是Col_L的子集時用左外鏈接。
四、 Col_R和Col_L彼此有交集但彼此互不爲子集時候用全外。
五、 求差操做的時候用聯合查詢。
4.2.MySQL聯合查詢union(字段不會增長)
聯合查詢:將屢次查詢的結果在記錄上進行拼接(字段不會增長),即查詢結果的合併。
基本語法:多條select語句構成,每一條select語句獲取的字段數必須嚴格一致,
Select a from A
Union
Select b from B
聯合查詢的意義:
1. 查詢同一張表,可是需求不一樣: 如查詢學生信息, 男生身高升序, 女生身高降序(最主要是用於對同一個表不一樣的操做)。
2. 多表查詢: 多張表的結構是徹底同樣的,具備相同的列,雖然沒有強制要求對應的列類型,順序一致,可是推薦將相對應的列類型和順序保持一致。
3.聯合查詢默認是去重(distinct)的,若是須要顯示所有則使用union all
4.在聯合查詢中,order by不能直接使用,須要對查詢語句使用括號才行;另外,要order by生效必須搭配limit,limit使用限定的最大數便可
4.3.MySQL子查詢
子查詢是指嵌入在其餘SQL語句中的select語句,這裏說的SQL語句能夠是delete,insert,update,select等語句,可包含多個關鍵字或條件(distinct,group by,order by,limit,函數等),子查詢必須始終出如今圓括號之內。固然子查詢並非嚴格劃分的,就是說咱們在某一次查詢中就可能使用到下面幾種分類的子查詢
4.3.1.按位置分類
子查詢(select語句)在外部查詢中出現的位置
1.from子查詢,子查詢跟在from以後
2.where子查詢,子查詢出現where條件中
3.exists子查詢,子查詢出如今exists裏面
4.3.2.按結果分類
根據子查詢獲得的數據進行分類(理論上講任何一個查詢獲得的結果均可以理解爲二維表)
4.3.2.1.標量子查詢
是指子查詢返回的是單一值的標量,如一個數字或一個字符串,也是子查詢中最簡單的返回形式; 能夠使用 = > < >= <= <> 這些操做符對子查詢的標量結果進行比較,一般子查詢的位置在比較式的右側
如:select * from student where height > (select avg(height) from student);找出大於平均身高的學生
4.3.2.2.列子查詢
指子查詢返回的結果集是 N 行一列,該結果一般來自對錶的某個字段查詢返回, 子查詢的結果爲多個值時就須要能夠使用 IN、ANY、SOME 和 ALL 操做符配合比較運算符進行比較。
如查找學生表中身高等於老師的身高的學生,select * from student where height in (select height from teacher);=any與in的效果是一致的,因此還能夠是select * from student where height =any (select height from teacher);
另外須要注意下any,some,all關鍵字的使用規則,any和some的使用基本差很少(有種說法就是some實際上是any的別名),惟一不一樣的是all,=some/=any就表示等於查詢結果的每個,=all沒有意義,=any 與 in 一樣的效果,<>all/!=all與not in一樣的效
4.3.2.3.行子查詢
指子查詢返回的結果集是一行 N 列,該子查詢的結果一般是對錶的某行數據進行查詢而返回的結果集。
好比咱們想查看學生表中編號和身高都等於老師表中的編號和身高的數據
select * from student where (number,height) = (select id,height form teacher where gender = ‘男’);
4.3.2.4.表子查詢
指子查詢返回的結果集是 N 行 N 列的一個表數據。
好比找出男生女生中身高最高的
select * from
(select * from student group by gender,height desc) as a
group by gender;
Exists子查詢,只要知足where條件的話,將展現全部的結果。
5.1.什麼是存儲引擎
引擎(Engine)是電子平臺上開發程序或系統的核心組件。利用引擎,開發者可迅速創建、鋪設程序所需的功能,或利用其輔助程序的運轉。通常而言,引擎是一個程序或一套系統的支持部分。常見的程序引擎有遊戲引擎,搜索引擎,殺毒引擎等。
簡單來講,存儲引擎就是指表的類型以及表在計算機上的存儲方式,每一種存儲引擎使用不一樣的存儲機制,索引技巧,鎖定水平。咱們能夠根據數據的特色來選擇不一樣的存儲引擎。
可以使用show engines;來查看MySQL提供的全部存儲引擎。
可以使用show variables like '%storage_engine%';來查看當前默認的存儲引擎。
5.2.存儲引擎分類
5.2.1.InnoDB存儲引擎
InnoDB給MySQL的表提供了事務處理、回滾、崩潰修復能力和多版本併發控制的事務安全。若是應用中須要執行大量的INSERT或UPDATE操做,則應該使用InnoDB,這樣能夠提升多用戶併發操做的性能。並且InnoDB對事務處理的能力,也是其餘存儲引擎不能比擬的。5.5之後版本的MySQL的默認存儲引擎就是InnoDB。
InnoDB存儲引擎中支持AUTO_INCREMENT。自動增加列的值不能爲空,而且值必須惟一。MySQL中規定自增列必須爲主鍵。在插入值的時候,若是自動增加列不輸入值,則插入的值爲自動增加後的值;若是輸入的值爲0或空(NULL),則插入的值也是自動增加後的值;若是插入某個肯定的值,且該值在前面沒有出現過,就能夠直接插入。
InnoDB還支持外鍵(FOREIGN KEY)。外鍵所在的表叫作子表,外鍵所依賴(REFERENCES)的表叫作父表。父表中被字表外鍵關聯的字段必須建立索引。當刪除、更新父表中的某條信息時,子表也必須有相應的改變,這是數據庫的參照完整性規則。
Innodb使用的行鎖(固然也支持表鎖),只對指定的行進行鎖定,其餘進程仍是能夠對錶中的其餘行進行操做的。所以行鎖能大大的減小數據庫操做的衝突,但有時會致使死鎖。
Innodb存儲引擎可將全部數據存放於ibdata*的共享表空間,也可將每張表存放於獨立的.ibd文件的獨立表空間。
共享表空間以及獨佔表空間都是針對innodb表的數據存儲而言的,ibdata1爲innodb引擎的存儲數據與索引的數據文件,ib_logfile0與ib_logfile1爲innodb引擎使用的日誌文件。
共享表空間: 某一個數據庫的全部的表數據,索引文件所有放在一個文件中,默認這個共享表空間的文件路徑在data目錄下。 默認的文件名爲:ibdata1 初始化爲10M。
獨立表空間: 每個表都將會生成以獨立的文件方式來進行存儲,每個表都有一個.frm表描述文件,還有一個.ibd文件,其中這個文件包括了單獨一個表的數據內容以及索引內容。
實例:咱們能夠在建立表是明確的指定engine,或者默認都是innodb。
create table test3(
id tinyint zerofill primary key
)engine= innodb
修改時:
alter table test3 engine = myisam
默認狀況下它的存儲位置也是在表的位置之中(即默認的存儲方式是獨立表空間);在配置文件my.ini中配置innodb_file_per_table=1(MySQL5.6.6之後默認的),能夠使用以下命令查看:
show variables lie ‘%innodb_file_per_table%’
InnoDB的優點在於提供了良好的事務處理、崩潰修復能力和併發控制。缺點是讀寫效率較差,佔用的數據空間相對較大。
5.2.2.MyISAM存儲引擎
MyISAM是MySQL中常見的存儲引擎,曾經是MySQL的默認存儲引擎【5.5之前默認是MyISAM,後面的默認就是InnoDB】。MyISAM是基於ISAM引擎發展起來的,增長了許多有用的擴展。
MyISAM的表存儲成3個文件。文件的名字與表名相同。拓展名爲frm、MYD、MYI。其中,frm文件存儲表的結構;MYD文件存儲數據,是MYData的縮寫;MYI文件存儲索引,是MYIndex的縮寫。
MyISAM使用的是表鎖。直接鎖定整張表,在鎖按期間,其餘進程沒法對該表進行寫操做,若是設置的是寫鎖,那麼其餘進程讀也不容許,所以myisam支持的併發量低。
MyISAM支持全文索引。
實例:
create table test2(
id tinyint unsigned primary key
)engine = myisam
修改時:
alter table test2 engine = innodb
5.2.3.MEMORY存儲引擎
MEMORY是MySQL中一類特殊的存儲引擎。它使用存儲在內存中的內容來建立表,並且數據所有放在內存中。這些特性與前面的兩個很不一樣。
每一個基於MEMORY存儲引擎的表實際對應一個磁盤文件。該文件的文件名與表名相同,類型爲frm類型。該文件中只存儲表的結構。而其數據文件,都是存儲在內存中,這樣有利於數據的快速處理,提升整個表的效率。值得注意的是,服務器須要有足夠的內存來維持MEMORY存儲引擎的表的使用。若是不須要了,能夠釋放內存,甚至刪除不須要的表。
MEMORY默認使用哈希索引。速度比使用B型樹索引快。固然若是你想用B型樹索引,能夠在建立索引時指定。
注意,MEMORY用到的不多,由於它是把數據存到內存中,若是內存出現異常就會影響數據。若是重啓或者關機,全部數據都會消失。所以,基於MEMORY的表的生命週期很短,通常是一次性的。
實例:
create table index2(
id tinyint not null)
engine = memory
因爲數據都是放在內存中的,因此就只有一個frm文件
5.2.4.怎樣選擇存儲引擎
InnoDB:支持事務處理,支持外鍵,支持崩潰修復能力和併發控制。若是須要對事務的完整性要求比較高(好比銀行),要求實現併發控制(好比售票),那選擇InnoDB有很大的優點。若是須要頻繁的更新、刪除操做的數據庫,也能夠選擇InnoDB,由於支持事務的提交(commit)和回滾(rollback)。
適用場景:
1)常常更新的表,適合處理多重併發的更新請求。
2)支持事務。
3)能夠從災難中恢復(經過bin-log日誌等)。
4)外鍵約束。只有他支持外鍵。
5)支持自動增長列屬性auto_increment。
MyISAM:插入數據快,空間和內存使用比較低(會對數據進行壓縮)。若是表主要是用於插入新記錄和讀出記錄,那麼選擇MyISAM能實現處理高效率。若是應用的完整性、併發性要求比 較低,也能夠使用。
適用場景:
1)不支持事務的設計,可是並不表明着有事務操做的項目不能用MyISAM存儲引擎,能夠在service層進行根據本身的業務需求進行相應的控制。
2)不支持外鍵的表設計。
3)查詢速度很快。
4)對錶進行加鎖的場景。
5)MyISAM極度強調快速讀取操做。
6)MyISAM中存儲了表的行數,因而SELECT COUNT(*) FROM TABLE時只須要直接讀取已經保存好的值而不須要進行全表掃描。若是表的讀操做遠遠多於寫操做且不須要數據庫事務的支持,那麼MyIASM也是很好的選擇。
MEMORY:全部的數據都在內存中,數據的處理速度快,可是安全性不高。若是須要很快的讀寫速度,對數據的安全性要求較低,能夠選擇MEMOEY。它對錶的大小有要求,不能創建太大的表。因此,這類數據庫只使用在相對較小的數據庫表。
注意,同一個數據庫也能夠使用多種存儲引擎能夠的表。若是一個表要求比較高的事務處理,能夠選擇InnoDB。這個數據庫中將查詢要求比較高的表選擇MyISAM存儲。若是該數據庫須要一個用於查詢的臨時表,能夠選擇MEMORY存儲引擎。
5.3.事務處理
5.3.1.事務的概念
事務由單獨單元的一個或多個SQL語句組成,在這個單元中,每一個MySQL語句是相互依賴的。而整個單獨單元做爲一個不可分割的總體,若是單元中某條SQL語句一旦執行失敗或產生錯誤,整個單元將會回滾。全部受到影響的數據將返回到事物開始之前的狀態;若是單元中的全部SQL語句均執行成功,則事物被順利執行。
事務就是一組原子性的sql,或者說一個獨立的工做單元。
事務就是說,要麼mysql引擎會所有執行這一組sql語句,要麼所有都不執行
5.3.2.事務的四個屬性
一、原子性(atomicity):事務是由一個或一組相互關聯的SQL語句組成,這些語句被認爲是一個不可分割的單元,事務是一個總體,要麼所有執行,要麼一句也不執行。
二、一致性(consistency):對於數據庫的修改是一致的,即多個用戶查的的數據是同樣的。一致性主要由mysql的日誌機制處理,他記錄數據的變化,爲事務恢復提供跟蹤記錄。
三、隔離性(isolation):每一個事務都有本身的空間,和其餘發生在系統中的事務隔離開來,就是說兩個事務不會交叉的執行,並且事務的結果只在他徹底被執行時才能看到,這就涉及到事務的隔離級別
四、持久性(durability):但提交了這個事務以後對數據的修改更新就是永久的,不會平白無故的回滾。當一個事務完成,數據庫的日誌已經被更新時,持久性便可發揮其特有的功效,在mysql中,若是系統崩潰或者數據存儲介質被破壞,經過日誌,系統可以恢復在重啓前進行的最後一次成功更新,能夠反應系統崩潰時處於執行過程的事物的變化。
5.3.3.事務的隔離性
1.在多用戶的時候使用孤立性級別是很重要的,這樣能夠保證這些事務互不影響,保證數據庫性能不受到影響。
2.mysql中提供的孤立級別有如下四種:
兩個命令行客戶端分別爲A,B;不斷改變A的隔離級別,在B端修改數據
(1)READ UNCOMMITTED(讀未提交)【遺留問題:是否是要設置的全局的都爲read uncommitted,若是隻設置了某一個會有效嗎?】
事務中的修改,即便沒有提交,對其餘會話也是可見的。
能夠讀取未提交的數據——髒讀。髒讀會致使不少問題,通常不使用這個隔離級別。
A:啓動事務,此時數據爲初始狀態
B:啓動事務,更新數據,但不提交
A:再次讀取數據,發現數據已經被修改了,這就是所謂的「髒讀」
B:回滾事務
A:再次讀數據,發現數據變回初始狀態
通過上面的實驗能夠得出結論,事務B更新了一條記錄,可是沒有提交,此時事務A能夠查詢出未提交記錄。形成髒讀現象。未提交讀是最低的隔離級別。
(2)READ COMMITTED(提交後讀或不可重複讀)
通常數據庫都默認使用這個隔離級別(mysql不是),這個隔離級別保證了一個事務若是沒有徹底成功(commit執行完),事務中的操做對其餘會話是不可見的。
A:啓動事務,此時數據爲初始狀態
B:啓動事務,更新數據,但不提交
A:再次讀數據,發現數據未被修改
B:提交事務
A:再次讀取數據,發現數據已發生變化,說明B提交的修改被事務中的A讀到了,這就是所謂的「不可重複讀」
通過上面的實驗能夠得出結論,已提交讀隔離級別解決了髒讀的問題,可是出現了不可重複讀的問題,即事務A在兩次查詢的數據不一致,由於在兩次查詢之間事務B更新了一條數據。已提交讀只容許讀取已提交的記錄,但不要求可重複讀,一致性發生變化。
(3)REPEATABLE READ(可重讀)【讀取的並非最新的數據,因此會出現幻讀,好比插入了一條記錄,讀取時由於沒有讀取最新的數據,因此沒有看到最新的記錄,當所有都提交後再插入相同的記錄時又會提示插入的數據已存在了,重複讀通常不出現幻讀,若是幻讀就結合鎖一塊兒使用,這就是爲何重複讀爲默認的isolation level】
別人對幻讀的理解:
幻讀,並非說兩次讀取獲取的結果集不一樣,幻讀側重的方面是某一次的 select 操做獲得的結果所表徵的數據狀態沒法支撐後續的業務操做。更爲具體一些:select 某記錄是否存在,不存在,準備插入此記錄,但執行 insert 時發現此記錄已存在,沒法插入,此時就發生了幻讀。
一個事務中屢次執行統一讀SQL,返回結果同樣。
A:啓動事務,此時數據爲初始狀態
B:啓動事務,更新數據,但不提交
A:再次讀取數據,發現數據未被修改
B:提交事務
A:再次讀取數據,發現數據依然未發生變化,這說明此次能夠重複讀了
B:插入一條新的數據,並提交
A:再次讀取數據,發現數據依然未發生變化,雖然能夠重複讀了,可是卻發現讀的不是最新數據,這就是所謂的「幻讀」
A:提交本次事務,再次讀取數據,發現讀取正常了
由以上的實驗能夠得出結論,可重複讀隔離級別只容許讀取已提交記錄,並且在一個事務兩次讀取一個記錄期間,其餘事務部的更新該記錄。但該事務不要求與其餘事務可串行化。例如,當一個事務能夠找到由一個已提交事務更新的記錄,可是可能產生幻讀問題(注意是可能,由於數據庫對隔離級別的實現有所差異)。像以上的實驗,就沒有出現數據幻讀的問題。
(4)SERIALIZABLE(序列化)
以序列的形式處理事務,只有事務提交後,用戶才能看到,可是該級別的隔離會影響mysql的性能,由於須要佔用大量的資源,以保證使大量事務在任意時間不被用戶看到,可能致使大量的超時現象和鎖競爭。
A:啓動事務,此時數據爲初始狀態
B:發現B此時進入了等待狀態,緣由是由於A的事務還沒有提交,只能等待(此時,B可能會發生等待超時)
A:提交事務
B:發現插入成功
serializable徹底鎖定字段,若一個事務來查詢同一份數據就必須等待,直到前一個事務完成並解除鎖定爲止。是完整的隔離級別,會鎖定對應的數據表格,於是會有效率的問題。
3.事務孤立級的查看和修改:
查看當前會話的隔離級別:select @@tx_isolation;
查看系統的隔離級別:select @@global.tx_isolation;
這隻當前會話隔離級別:set session transaction isolation level 設置的隔離級別
設置全局隔離級別:set global transaction isolation level 設置的隔離級別;
四種隔離級別:read uncommitted, read committed ,repeatable read ,serializable
三種數據問題:髒讀,不可重複讀,幻讀
髒讀(Drity Read):某個事務已更新一份數據,另外一個事務在此時讀取了同一份數據,因爲某些緣由,前一個RollBack了操做,則後一個事務所讀取的數據就會是不正確的
不可重複讀(Non-repeatable read):在一個事務的兩次查詢之中數據不一致,這多是兩次查詢過程當中間插入了一個事務更新的原有的數據。【另一個事務對數據進行更新和刪除操做】
幻讀(Phantom Read):在一個事務的兩次查詢中數據筆數不一致,例若有一個事務查詢了幾列(Row)數據,而另外一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。【另一個事務對數據進行插入操做】
5.4.鎖
從上面咱們能夠看出,各個不一樣隔離級別的特色,爲防止更新丟失,並不能單靠數據庫事務控制器來解決,須要應用程序對要更新的數據加必要的鎖來解決。
5.4.1.什麼是併發控制
併發控制:當多個鏈接對記錄進行修改時保證數據的一致性和完整性(好比兩個不一樣的用戶a和b登陸數據庫,同時,a對test表中的id爲20的數據進行查詢,b對test表中id爲20的數據進行刪除,這時能夠會出現錯誤)
5.4.2.鎖的定義
鎖是計算機協調多個進程或線程併發訪問某一資源的機制。
如何保證數據併發訪問的一致性、有效性是鎖在數據庫必須解決的一個問題,鎖衝突也是影響數據庫併發訪問性能的一個重要因素。從這個角度來講,鎖對數據庫而言顯得尤爲重要,也更加複雜。
5.4.3.鎖是如何運做的
事務T在對某個數據對象(如表、記錄等)操做以前,先向系統發出請求,對其加鎖,加鎖後事務T就對數據庫對象有必定的控制,在事務T釋放它的鎖以前,其餘事務不能更新此數據對象。
5.4.4.鎖定機制的分類
鎖定機制就是數據庫爲了保證數據的一致性而使各類共享資源在被併發訪問訪問變得有序所設計的一種規則。MySQL數據庫因爲其自身架構的特色,存在多種數據存儲引擎,每種存儲引擎所針對的應用場景特色都不太同樣,爲了知足各自特定應用場景的需求,每種存儲引擎的鎖定機制都是爲各自所面對的特定場景而優化設計,因此各存儲引擎的鎖定機制也有較大區別。
5.4.4.1.共享鎖( S鎖)
共享鎖也稱爲讀鎖,讀鎖容許多個鏈接能夠同一時刻併發的讀取同一資源,互不干擾;總的來講就是會阻塞其餘事務修改數據。
5.4.4.2.排他鎖( X鎖)
排他鎖也稱爲寫鎖,一個寫鎖會阻塞其餘的寫鎖或讀鎖,保證同一時刻只有一個鏈接能夠寫入數據,同時防止其餘用戶對這個數據的讀寫;總的來講會阻塞其餘事務讀和寫。
5.4.4.3.鎖策略(鎖的粒度)
鎖的開銷是較爲昂貴的,鎖策略其實就是保證了線程安全的同時獲取最大的性能之間的平衡策略。
一、mysql鎖策略:talbe lock(表鎖)
總的來講:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。
詳細:和行級鎖定相反,表級別的鎖定是MySQL各存儲引擎中最大顆粒度的鎖定機制。該鎖定機制最大的特色是實現邏輯很是簡單,帶來的系統負面影響最小。因此獲取鎖和釋放鎖的速度很快。因爲表級鎖一次會將整個表鎖定,因此能夠很好的避免困擾咱們的死鎖問題。
缺陷:鎖定顆粒度大所帶來最大的負面影響就是出現鎖定資源爭用的機率也會最高,導致併發度大打折扣。
具體狀況是:若一個用戶正在執行寫操做,會獲取排他的「寫鎖」,這可能會鎖定整個表,阻塞其餘用戶的讀、寫操做;
若一個用戶正在執行讀操做,會先獲取共享鎖「讀鎖」,這個鎖運行其餘讀鎖併發的對這個表進行讀取,互不干擾。只要沒有寫鎖的進入,讀鎖能夠是併發讀取統一資源的。
二、mysql鎖策略:row lock(行鎖)
總的來講:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
詳細:行級鎖定最大的特色就是鎖定對象的顆粒度很小,也是目前各大數據庫管理軟件所實現的鎖定顆粒度最小的。因爲鎖定顆粒度很小,因此發生鎖定資源爭用的機率也最小,可以給予應用程序儘量大的併發處理能力而提升一些須要高併發應用系統的總體性能。
缺陷:因爲鎖定資源的顆粒度很小,因此每次獲取鎖和釋放鎖須要作的事情也更多,帶來的消耗天然也就更大了。此外,行級鎖定也最容易發生死鎖。
活鎖:就是當鎖釋放後,老是會去執行最新在等待的事務,因此會致使中間有些等待的事務一致處於循環等待下去的狀態。
5.4.4.4.其餘
活鎖
若是事務T1封鎖了數據對象R後,事務T2也請求封鎖R,因而T2等待,接着T3也請求封鎖R。當T1釋放了加載R上的鎖後,系統首先批准T3的請求,T2只能繼續等待。接着T4也請求封鎖R,T3釋放R上的鎖後,系統又批轉了T4的請求。這樣的一直循環下去,事務T2就只能永遠等待了,這樣狀況叫活鎖。
死鎖
當兩個事務分別鎖定了兩個單獨的對象,這時每個事務都要求在另外一個事務鎖定的對象上得到一個鎖,所以每個事務都必須等待另外一個事務釋放佔有的鎖。這就發生了死鎖
意向鎖:解決行鎖與表鎖的衝突
事務A鎖住了表中的一行,讓這一行只能讀,不能寫。以後,事務B申請整個表的寫鎖。若是事務B申請成功,那麼理論上它就能修改表中的任意一行,這與A持有的行鎖是衝突的。數據庫須要避免這種衝突,就是說要讓B的申請被阻塞,直到A釋放了行鎖。數據庫要怎麼判斷這個衝突呢?
普通認爲兩步:step1:判斷表是否已被其餘事務用表鎖鎖表。step2:判斷表中的每一行是否已被行鎖鎖住。可是這樣的方法效率很低,由於要遍歷整個表。
因此就有了意向鎖的存在。
在乎向鎖存在的狀況下,事務A必須先申請表的意向共享鎖,成功後再申請一行的行鎖。
在乎向鎖存在的狀況下,兩步驟爲:step1:判斷表是否已被其餘事務用表鎖鎖表。step2:發現表上有意向共享鎖,說明表中有些行被共享行鎖鎖住了,所以,事務B申請表的寫鎖會被阻塞。
注意:申請意向鎖的動做是數據庫完成的,就是說,事務A申請一行的行鎖的時候,數據庫會自動先開始申請表的意向鎖,不須要咱們程序員使用代碼來申請。
意向鎖是一種表級鎖,鎖的粒度是整張表。結合共享與排他鎖使用,分爲意向共享鎖(IS)和意向排他鎖(IX)。意向鎖爲了方便檢測表級鎖和行級鎖之間的衝突,故在給一行記錄加鎖前,首先給該表加意向鎖。也就是同時加意向鎖和行級鎖
MyISAM引擎的鎖機制
MyISAM只有表鎖,其中又分爲讀鎖和寫鎖,即表共享讀鎖(table read lock)和表獨佔寫鎖(table write lock)
首先明確:
1.MySQL認爲寫請求通常比讀請求重要,若是兩個事務同時請求,優先執行寫。
2.MyISAM在執行查詢語句(SELECT)前,會自動給涉及的全部表加讀鎖,在執行更新操做(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程並不須要用戶干預,所以用戶通常不須要直接用LOCK TABLE命令給MyISAM表顯式加鎖【由於咱們平時執行的select,update等語句時間比較短,因此執行完就解鎖表了,因此咱們看不出來表被自動加鎖了的】
給MyISAM表顯示加鎖,通常是爲了在必定程度模擬事務操做,實現對某一時間點多個表的一致性讀取。例如,有一個訂單表orders,其中記錄有各訂單的總金額total,同時還有一個訂單明細表order_detail,其中記錄有各訂單每一產品的金額小計 subtotal,假設咱們須要檢查這兩個表的金額合計是否相符,可能就須要執行以下兩條SQL:
Select sum(total) from orders;
Select sum(subtotal) from order_detail;
這時,若是不先給兩個表加鎖,就可能產生錯誤的結果,由於第一條語句執行過程當中,order_detail表可能已經發生了改變。所以,正確的方法應該是:
Lock tables orders read local, order_detail read local;
Select sum(total) from orders;
Select sum(subtotal) from order_detail;
Unlock tables;
注意事項:
在用LOCK TABLES給表顯式加表鎖時,必須同時取得全部涉及到表的鎖,而且MySQL不支持鎖升級。也就是說,在執行LOCK TABLES後,只能訪問顯式加鎖的這些表【若是表使用別名,也須要對別名進行加鎖】,不能訪問未加鎖的表;同時,若是加的是讀鎖,那麼只能執行查詢操做,而不能執行更新操做。其實,在自動加鎖的狀況下也基本如此,MyISAM老是一次得到SQL語句所須要的所有鎖【即若是要對對個表加鎖,就是一次性加,否則只對最後面的語句中的表進行加鎖】。這也正是MyISAM表不會出現死鎖(Deadlock Free)的緣由。
實例:【對錶進行加鎖後,只能顯示訪問加鎖的表】
對錶test進行讀鎖定
查詢表test【能夠正常的查詢】
查詢其餘表時報錯【提示表test1沒有在鎖定表中】
用test表的別名進行查詢一樣會報相同的異常
當對錶的別名鎖定後,使用別名便可查詢【查詢語句是:select * from test as t; 可是查詢原表也會報異常,select * from test一樣會提示沒在鎖定表中的錯誤】
實例:【一次得到SQL語句所須要的所有鎖】
先鎖定表test後,再鎖定test1
而後查詢表test
查詢表test1
從上面咱們能夠看出,最後鎖定的是表test1,即最後的那個鎖定語句才生效的,若是咱們須要同時鎖定多張表,那麼就應該一次性鎖定
這樣咱們均可以對錶test,test1進行查詢了
併發插入(Concurrent Inserts)
上文提到過MyISAM表的讀和寫是串行的,但這是就整體而言的。在必定條件下,MyISAM表也支持查詢和插入操做的併發進行。
MyISAM存儲引擎有一個系統變量concurrent_insert,專門用以控制其併發插入的行爲,其值分別能夠爲0(NEVER)、1(AUTO)或2(ALWAYS)。
當concurrent_insert設置爲0時,不容許併發插入。
當concurrent_insert設置爲1時,若是MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM容許在一個進程讀表的同時,另外一個進程從表尾插入記錄。這也是MySQL的默認設置。
當concurrent_insert設置爲2時,不管MyISAM表中有沒有空洞,都容許在表尾併發插入記錄。
查看concurrent_insert變量:show global variables like ‘%concurrent_insert%’ 或者 select @@concurrent_insert
設置concurrent_insert變量:set global concurrent_insert = 1
實例:【這裏咱們直接將concurrent_insert = 2來方便直觀的演示】
A:將concurrent_insert = 2,並查看到表xiong的數據
B:查看錶xiong的數據
A:鎖定表xiong,使用:lock table xiong read local;
B:向xiong表中查詢一條數據【能夠直接插入成功,不須要等待】
總結:
上面的例子在LOCK TABLES時加了「local」選項,【可是這個只能是加的讀鎖(lock table read),而寫鎖是加不了local的】,其做用就是在知足MyISAM表併發插入條件的狀況下,容許其餘用戶在表尾併發插入記錄。當全局變量concurrent_insert爲0時,一個session鎖定了表,另一個session就不能進行任何插入或修改操做;當全局變量concurrent_insert爲1時(默認狀況concurrent_insert的值就爲1),一個session鎖定了表,另一個session能夠對鎖定的表(可是要確保這個表的中間沒有被刪除的行)進行插入操做;當全局變量concurrent_insert爲2時(默認狀況concurrent_insert的值就爲1),一個session鎖定了表,另一個session能夠對沒鎖定的表進行插入操做。
MyISAM的鎖調度
MyISAM存儲引擎的讀鎖和寫鎖是互斥的,讀寫操做是串行的。那麼,一個進程請求某個 MyISAM表的讀鎖,同時另外一個進程也請求同一表的寫鎖,MySQL如何處理呢?答案是寫進程先得到鎖。不只如此,即便讀請求先到鎖等待隊列,寫請求後到,寫鎖也會插到讀鎖請求以前!這是由於MySQL認爲寫請求通常比讀請求要重要。這也正是MyISAM表不太適合於有大量更新操做和查詢操做應用的緣由,由於,大量的更新操做會形成查詢操做很難得到讀鎖,從而可能永遠阻塞。這種狀況有時可能會變得很是糟糕!幸虧咱們能夠經過一些設置來調節MyISAM 的調度行爲。
經過指定啓動參數low-priority-updates,使MyISAM引擎默認給予讀請求以優先的權利。
經過執行命令SET LOW_PRIORITY_UPDATES=1,使該鏈接發出的更新請求優先級下降。
經過指定INSERT、UPDATE、DELETE語句的LOW_PRIORITY屬性,下降該語句的優先級。
查看變量:select @@low_priority_updates;或者show global variables like ‘%low_priority%’
設置變量:set @@low_priority_updates = 1;
雖然上面3種方法都是要麼更新優先,要麼查詢優先的方法,但仍是能夠用其來解決查詢相對重要的應用(如用戶登陸系統)中,讀鎖等待嚴重的問題。
另外,MySQL也提供了一種折中的辦法來調節讀寫衝突,即給系統參數max_write_lock_count設置一個合適的值,當一個表的讀鎖達到這個值後,MySQL就暫時將寫請求的優先級下降,給讀進程必定得到鎖的機會。
上面已經討論了寫優先調度機制帶來的問題和解決辦法。這裏還要強調一點:一些須要長時間運行的查詢操做,也會使寫進程「餓死」!所以,應用中應儘可能避免出現長時間運行的查詢操做,不要總想用一條SELECT語句來解決問題,由於這種看似巧妙的SQL語句,每每比較複雜,執行時間較長,在可能的狀況下能夠經過使用中間表等措施對SQL語句作必定的「分解」,使每一步查詢都能在較短期完成,從而減小鎖衝突。若是複雜查詢不可避免,應儘可能安排在數據庫空閒時段執行,好比一些按期統計能夠安排在夜間執行。
Innodb引擎的鎖機制
對於UPDATE、DELETE、INSERT語句,Innodb會自動給涉及的數據集加排他鎖(X);對於普通SELECT語句,Innodb不會加任何鎖。
InnoDB這種行鎖實現特色意味着:只有經過索引條件檢索數據,innoDB才使用行級鎖,不然InnoDB將使用表鎖,在實際開發中應當
Select * from tb_name where... for update; :排它鎖
Select * from tb_name where... lock in share mode; :共享鎖
一樣能夠使用lock table tb_name read等方式來給INNODB的表添加表鎖,可是AUTOCOMMIT設爲0,不然MySQL不會給表加鎖;事務結束前,不要用UNLOCAK TABLES釋放表鎖,由於UNLOCK TABLES會隱含地提交事務;COMMIT或ROLLBACK產不能釋放用LOCAK TABLES加的表級鎖,必須用UNLOCK TABLES釋放表鎖,正確的方式見以下語句。
SET AUTOCOMMIT=0;
LOCAK TABLES t1 WRITE, t2 READ, ...;
[do something with tables t1 and here];
COMMIT;
UNLOCK TABLES;
6.1.什麼是索引
索引是存儲引擎用於快速找到記錄的一種數據結構
理解索引最簡單的辦法就是去看一看一本書的"索引"(目錄)部分. 經過找到目錄中對應的特定主題的頁碼,可快速定位到你要找的主題.
mysql中也同樣,數據查找時,先看看查詢條件是否命中某條索引,符合則經過索引找到相關數據返回,不符合則須要全表掃描,找到與條件符合的行返回.
6.2.MySQL中索引的優勢和缺點和使用原則
6.2.1.優勢
一、全部的MySql列類型(字段類型)均可以被索引,也就是能夠給任意字段設置索引
二、大大加快數據的查詢速度
6.2.2.缺點
一、建立索引和維護索引要耗費時間,而且隨着數據量的增長所耗費的時間也會增長
二、索引也須要佔空間,咱們知道數據表中的數據也會有最大上限設置的,若是咱們有大量的索引,索引文件可能會比數據文件更快達到上限值
三、當對錶中的數據進行增長、刪除、修改時,索引也須要動態的維護,下降了數據的維護速度。
6.2.3.使用原則
6.2.3.1.索引選取類型
經過上面說的優勢和缺點,咱們能夠知道,並非每一個字段度設置索引就好,也不是索引越多越好,而是須要本身合理的使用。
一、對常常更新的表就避免對其進行過多的索引,對常常用於查詢的字段應該建立索引,
二、數據量小的表最好不要使用索引,由於因爲數據較少,可能查詢所有數據花費的時間比遍歷索引的時間還要短,索引就可能不會產生優化效果。
三、在一同值少的列上(字段上)不要創建索引,好比在學生表的"性別"字段上只有男,女兩個不一樣值。相反的,在一個字段上不一樣值較多但是創建索引。
6.2.3.2.什麼場景不適合建立索引
第一,對於那些在查詢中不多使用或者參考的列不該該建立索引。這是由於,既然這些列不多使用到,所以有索引或者無索引,並不能提升查詢速度。相反,因爲增長了索引,反而下降了系統的維護速度和增大了空間需求。
第二,對於那些只有不多數據值的列也不該該增長索引。由於原本結果集合就是至關於全表查詢了,因此沒有必要。這是由於,因爲這些列的取值不多,例如人事表的性別列,在查詢的結果中,結果集的數據行佔了表中數據行的很大比例,即須要在表中搜索的數據行的比例很大。增長索引,並不能明顯加快檢索速度。
第三,對於那些定義爲text, image和bit數據類型的列不該該增長索引。這是由於,這些列的數據量要麼至關大,要麼取值不多。
第四,當修改性能遠遠大於檢索性能時,不該該建立索引(即常常作增刪改操做的表)。這是由於,修改性能和檢索性能是互相矛盾的。當增長索引時,會提升檢索性能,可是會下降修改性能。當減小索引時,會提升修改性能,下降檢索性能。因 此,當修改性能遠遠大於檢索性能時,不該該建立索引。
第五,不會出如今where條件中的字段不應創建索引。
第六,當表記錄太少時不該該創建索引
6.2.3.3.什麼場景適合建立索引
表的主鍵、外鍵必須有索引;
數據量超過300的表應該有索引;
常常與其餘表進行鏈接的表,在鏈接字段上應該創建索引(其實這裏說的就是外鍵列)
常常出如今Where子句中的字段,加快判斷速度,特別是大表的字段,應該創建索引,創建索引
常常用到排序的列上,由於索引已經排序。
常常用在範圍內搜索的列上建立索引,由於索引已經排序了,其指定的範圍是連續的
常常用到搜索的列上,能夠加快搜索的速度
6.3.索引的分類
索引主要分爲單列索引(普通索引,惟一索引,主鍵索引)、組合索引、全文索引、空間索引
6.3.1.單列索引
1.普通索引:MySQL中基本索引類型,沒有什麼限制,容許在定義索引的列中插入重複值和空值,純粹爲了查詢數據更快一點。
2.惟一索引:索引列中的值必須是惟一的,可是容許爲空值。
3.主鍵索引:是一種特殊的惟一索引,不容許有空值。
6.3.2.組合索引
在表中的多個字段組合上建立的索引,只有在查詢條件中使用了這些字段的左邊字段時,索引纔會被使用,使用組合索引時遵循最左前綴集合。
6.3.2.1.有哪些狀況能夠命中索引
左前綴:如組合索引爲(name,age,gender),那麼(name);(name,age);(name,age,gender)三種方式就會命中索引
對於使用 like 的查詢,後面若是是常量而且只有%號不在第一個字符,索引纔可能會被使用,好比select * from index2 where name like 'xiong%'會命中索引,可是select * from index2 where name like '%xiong%'不會命中索引
通常索引都要求爲not null的,因此使用select * from index2 where name is null/ is not null不會命中到索引
用 or 分割開的條件,須要用and鏈接的才能用到索引,如explain select * from test1 where name = ‘xiong’ and age =23能夠命中索引,可是explain select * from test1 where name = ‘xiong’ or age =23不能命中索引
若是列是字符型,傳入的是數字,而不是‘’(加雙引號)的內容,不會使用索引,如explain select * from test1 where name = 23這樣就不會命中索引
若是查詢條件中的索引列加入了函數或者進行運算也不會命中索引,如xiong的組合索引爲:(age,gender)那麼explain select * from xiong where age+1=20就不會命中索引
6.3.3.全文索引
全文索引是爲了使得「關鍵詞搜索」功能更加的高效能,如提升站內搜索效率,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT類型字段上使用全文索引,mysql如今通常使用的版本其實也支持全文索引,索引類型爲fulltext,只不過他的功能還不夠強大,對中文的支持不夠好,沒法智能分詞
須要工做的程序:索引程序,分詞程序,數據庫。
若是對大的文本進行搜索,使用全文索引而不用使用 like ‘%…%’。
6.3.4.空間索引
空間索引是對空間數據類型的字段創建的索引,MySQL中的空間數據類型有四種,GEOMETRY、POINT、LINESTRING、POLYGON。在建立空間索引時,使用SPATIAL關鍵字。
要求,引擎爲MyISAM,建立空間索引的列,必須將其聲明爲NOT NULL
6.4.索引操做
6.4.1.建立索引
6.4.1.1.建立普通索引
create table tb_name(
id tinyint not null,
name varchar(20) not null,
key/index [索引名](id)) #這裏使用index或者key均可以
);
建立普通索引時,使用key和index均可以,另外索引名咱們能夠本身添加,若是建立時沒有寫索引名,那麼MySQL會自動幫咱們用字段名看成索引名。
6.4.1.2.建立惟一索引
create table tb_name(
id tinyint not null,
name varchar(20) not null,
unique index/key [索引名](id) #這裏使用index或者key均可以
);建立惟一索引時,使用key和index均可以,另外索引名咱們能夠本身添加,若是建立時沒有寫索引名,那麼MySQL會自動幫咱們用字段名看成索引名。
6.4.1.3.建立主鍵索引
Create table tb_name(
id tinyint not null,
name varchar(20) not null,
Primary key(id) #記得使用的是primary key ,若是使用primary index不行
);
primary key ,unique key,foreign key 三個建立後會自動建立索引,因此建立這三個索引實際上是和建立鍵時一致的。
key 和index的區別:
key 是數據庫的物理結構,它包含兩層意義,一是約束(偏重於約束和規範數據庫的結構完整性),二是索引(輔助查詢用的)
index是數據庫的物理結構,它只是輔助查詢的,它建立時會在另外的表空間(mysql中的innodb表空間)以一個相似目錄的結構存儲。索引要分類的話,分爲前綴索引、全文本索引等;
所以,索引只是索引,它不會去約束索引的字段的行爲(那是key要作的事情)
6.4.1.4.建立單列索引
這個其實就不用在說了,前面幾個就是單列索引
6.4.1.5.建立組合索引
create table tb_name(
id tinyint not null,
name varchar(20) not null,
age tinyint not null,
Info varchar(100),
index(id,name,age)
);
組合索引就是在多個字段上建立一個索引
組合索引就是聽從了最左前綴,利用索引中最左邊的列集來匹配行,這樣的列集稱爲最左前綴,不明白不要緊,舉幾個例子就明白了,例如,這裏由id、name和age三個字段構成的索引,索引行中就按id/name/age的順序存放,索引能夠索引下面字段組合(id,name,age)、(id,name)或者(id)。若是要查詢的字段不構成索引最左面的前綴,那麼就不會使用索引,好比,age或者(name,age)組合就不會使用索引查詢。
例如在tb表中:
explain select * from tb where id = 1 and name = 'xiong'\G;
在tb表中,查詢(age,name)字段,這樣就不會使用索引查詢。來看看結果
explain select * from tb where age = 3 and name = ‘ying’\G;
6.4.1.6.建立全文索引
全文索引能夠用於全文搜索,但只有MyISAM存儲引擎支持FULLTEXT索引,而且只爲CHAR、VARCHAR和TEXT列服務。索引老是對整個列進行,不支持前綴索引
create table tb(
Id tinyint not null,
Name varchar(20) not null,
Age tinyint not null,
Info varchar(255),
Fulltext index Fulltxt(info)
)engine = myisam;
在使用全文搜索時,須要藉助MATCH函數,而且其全文搜索的限制比較多,好比只能經過MyISAM引擎,好比只能在CHAR,VARCHAR,TEXT上設置全文索引。好比搜索的關鍵字默認至少要4個字符,好比搜索的關鍵字過短就會被忽略掉。
6.4.1.7.建立空間索引
空間索引也必須使用MyISAM引擎, 而且空間類型的字段必須爲非空。 這個空間索引具體能幹嗎我也不知道,可能跟遊戲開發有關,可能跟別的東西有關,等遇到了天然就知道了,如今只要求可以建立出來
6.4.2.在已經存在的表上建立索引
6.4.2.1.爲表添加索引
格式:ALTER TABLE 表名 ADD[UNIQUE|FULLTEXT|SPATIAL] [INDEX|KEY] [索引名] (索引字段名)[ASC|DESC]
Alter table tb_name add index(column1)
Alter table tb_name add unique index(column1)
Alter table tb_name add primary key(columnn1)
Alter table tb_name add index(column1,column2)
Alter table tb_name add fulltext index(column1)
Alter table tb_name add spatial index(column1)
6.4.2.2.使用CREATE INDEX建立索引
格式:CREATE [UNIQUE|FULLTEXT|SPATIAL] [INDEX|KEY] 索引名稱 ON 表名(建立索引的字段名[length])[ASC|DESC]
Create index 索引名稱 on tb_name(column)
Create unique index 索引名稱 on tb_name(column)
create primary key 索引名稱 on tb_name(column)
6.4.3.刪除索引
6.4.3.1.格式一
Alter table tb_name drop index index_name;(經過show index from tb_name來查看index_name)
6.4.3.2.格式二
Drop index index_name on tb_name;(經過show index from tb_name來查看index_name)
7.1.變量
7.1.1.用戶自定義變量
7.1.1.1.局部變量
局部變量通常用在sql語句塊中,好比存儲過程的begin/end。其做用域僅限於該語句塊,在該語句塊執行完畢後,局部變量就消失了。
局部變量通常用declare來聲明,能夠使用default來講明默認值。
create function add( in a int, in b int) returns int
begin
declare c int default 0;
set c = a + b;
return c;
End
7.1.1.2.用戶變量
用戶變量的做用域要比局部變量要廣。用戶變量能夠做用於當前整個鏈接,可是噹噹前鏈接斷開後,其所定義的用戶變量都會消失,主要是加有@符號的變量。
用戶變量使用以下(這裏咱們無須使用declare關鍵字進行定義,能夠直接這樣使用:select @變量名來查看用戶變量)
第一種是執行SET語句
SET @var_name = expr [, @var_name = expr] ...
對於SET,能夠使用=或:=做爲分配符。分配給每一個變量的expr能夠爲整數、實數、字符串或者NULL值。
實例:
set @a = 32; 使用【=】的方式定義一個用戶變量a並賦值爲32
select @a; 查看用戶變量a的值
set @b := 99; 使用【:=】的方式定義一個用戶變量b並賦值爲99
select @b; 查看用戶變量b的值
第二種是使用SELECT語句
使用SELECT定義用戶變量只能使用:=做爲分配符(由於在非SET語句中 = 被視爲一個‘比較操做符’)
實例:
select @a := 99+1,@a; 使用select定義了變量a,並查看a的值
7.1.2.系統變量
MySQL服務器維護兩種變量:全局變量影響服務器總體操做;會話變量影響具體客戶端鏈接的操做。
7.1.2.1.全局變量
當服務器啓動時,它將全部全局變量初始化爲默認值。這些默認值能夠在配置文件(my.ini)中或在命令行中指定的選項進行更改。全局變量做用於server的整個生命週期,可是不能重啓。即重啓後全部設置的全局變量均失效。要想讓全局變量重啓後繼續生效,須要更改相應的配置文件。服務器啓動後,經過鏈接服務器並執行SET GLOBAL var_name語句,能夠動態更改這些全局變量。要想更改全局變量,必須具備SUPER權限。
要想查看一個GLOBAL變量的值,使用下面的語法:
mysql> SELECT @@global.sort_buffer_size;
mysql> SHOW GLOBAL VARIABLES like 'sort_buffer_size';
要想設置一個GLOBAL變量的值,使用下面的語法:
mysql> SET GLOBAL sort_buffer_size=value;
mysql> SET @@global.sort_buffer_size=value;
7.1.2.2.會話變量
服務器還爲每一個鏈接的客戶端維護一系列會話變量。在鏈接時使用相應全局變量的當前值對客戶端的會話變量進行初始化,也就是說,若是在創建會話之後,沒有手動更改過會話變量與全局變量的值,那全部這些變量的值都是同樣的(與全局變量的值同樣)。對於動態會話變量,客戶端能夠經過SET SESSION var_name語句更改它們。設置會話變量不須要特殊權限,但客戶端只能更改本身的會話變量,而不能更改其它客戶端的會話變量。當前鏈接斷開後,其設置的全部會話變量均會自動釋放
要想查看一個SESSION變量的值,使用下面的語法:
mysql> SELECT @@sort_buffer_size;
mysql> SELECT @@session.sort_buffer_size;
mysql> SHOW SESSION VARIABLES like 'sort_buffer_size';
要想設置一個SESSION變量的值,使用下面的語法:
mysql> SET SESSION sort_buffer_size=value;
mysql> SET @@session.sort_buffer_size=value;
mysql> SET sort_buffer_size=value;
7.1.2.3.用戶變量與會話變量的區別
相同點:
1.用戶變量和會話變量在當前客戶端退出後都會自動釋放
2.修改只對當前客戶端有影響,不會影響其餘的客戶端
不一樣點:
1.用戶變量是用戶自身定義的變量
2.會話變量是在客戶端創建鏈接時會建立一系列會話變量,並以全局變量的當前值初始化會話變量(會話變量至關於系統全局變量的副本)
7.2.什麼是函數
mysql中的函數與存儲過程相似,都是一組SQL集;
7.3.與存儲過程的區別
1.存儲過程實現的功能相對複雜,函數針對性較強,
2.存儲過程能夠返回多個值,函數只能有一個返回值
3.存儲過程通常獨立執行,函數能夠做爲 sql 語句的組成部分來出現
4.函數能夠對數據庫或表進行操做,而存儲過程通常是對數據表中的數據進行操做
7.4.mysql自帶函數
7.5.自定義函數
兩個必要的條件:
1.參數:參數並不是是每一個函數所必須的,有的函數就沒有參數,參數能夠是任意類型的,理論上參數的個數不得超過1024個
2.返回值:函數必須有返回值,可是隻能返回一個值,返回值一樣能夠是任意類型的
查看函數:
1. show function status [like 'pattern']; -- 查看全部自定義函數, 自定義函數只能在本數據庫使用。
2. show create function 函數名; -- 查看函數建立語句
刪除函數:
drop function 函數名;
建立不帶參數的自定義函數:
create function f()
returns varchar(20)
return date_format(now(),'%y年%m月%d日 %h時%i分%s秒')
建立帶參數的自定義函數
-- 計算1 ~ 指定數據之間的和
delimiter //
create function my_sum(x int) returns int
begin
set @i = 1;
set @sum = 0;
while @i <= x
do
set @sum = @sum + @i;
set @i = @i + 1;
end while;
return @sum;
end
//
delimiter ;
調用:
select my_sum(20);
建立具備複合體的複雜自定義函數:
-- 求1 ~ 指定數以前的和,但5的倍數不加
delimiter $$
create function my_sum2(x int) returns int
begin
declare i int default 1;
declare sum int default 0;
sumwhile:while i <= x do
if i % 5 = 0 then
set i = i + 1;
iterate sumwhile;
end if;
set sum = sum + i;
set i = i + 1;
end while;
return sum;
end
$$
delimiter ;
7.6.經常使用函數
7.6.1.MySQL字符函數
7.6.1.1.ltrim()
刪除字符最左邊的空格
select ltrim(' xiong') =>xiong
7.6.1.2.rtrim()
刪除字符最右邊的空格
selct rtrim(' xiong ') => xiong
7.6.1.3.trim()
能夠選擇刪除字符最左邊或最右邊的其餘字符
1.select trim(leading '?' from '??xiong??') =>xiong??(前導,刪除前面的)
2.select trim(trailing '?' from '??xiong??') =>??xiong (後導,刪除後面的)
3.select trim(both '?' from '??xiong??') =>xiong (刪除先後的)須要注意的是,若是是select trim(both '??’ from '???xiong???')的話,結果爲=>?xiong?,還有一個?是沒有刪除的,由於後面的?能去除的恰好是前面?的倍數。
7.6.1.4.substring()
截取字符串
select substring('xiong',1,2) =>xi 能夠看出mysql中下標是從1開始而不是從0開始的
select substring('xiong',2) =>iong 若是沒有第三個參數,則截取到最後
select substring('xiong',-1) =>g 能夠看出用負數從最後開始,第一個爲-1,沒有第三個參數,截取到最後
7.6.1.5.not like 或者like
咱們知道與like常常一塊兒使用的通配符有以下兩個:%:表示任意個數的字符; _ :表示任意一個字符。
但有時,要匹配的模式包含通配符,例如10%,_20等。在這些狀況下,能夠使用ESCAPE子句指定轉義字符,以便MySQL將通配符解釋爲文字字符。若是沒有明確指定轉義字符,默認的轉義字符是反斜槓"\"
如:select * from test1 where name like ‘%\%%’; 就表示查找name包含%的,使用escape
select * from test1 name like '%1%%' escape '1';
或者
select * from test1 name like '%x%%' escape 'x';
7.6.2.mysql數值運算符合函數
7.6.2.1.ceil()
向上取整,即往大的方向取
select ceil(3.001) =>4
select ceil(-3.2) => -3
7.6.2.2.floor()
向下取整,即往小的方向取
select floor(3.99) =>3
select floor(-3.2) =>-4
7.6.2.3.div
整數整除,除了以後取整,與上面不一樣的是無論是正負數都是去掉小數部分,取整數部分
select 20 div 3 =>6
select -20 div 3 =>-6
7.6.2.4.mod
和%同樣,表示取餘數
select 5 mod 3 =>2
sleect 5 % 3 =>2
slelct 5.3 mod 3 =>2.3
7.6.2.5.power()
乘方
select power(3,3) =>27
7.6.2.6.round()
四捨五入,能夠指定保留小數的位數
select round(4.325,2) =>4.33
7.6.2.7.truncate()
截斷,一樣也能夠指定截斷保留幾個小數
select truncate(323.437,2) =>323.43
7.6.2.8.not / between ... and
在或不在範圍以內,閉區間,0表示假,1表示真
select 15 between 1 and 20 =>
7.6.2.9.is null / is not null
爲null或不爲null,0表示假,1表示真
select null is null =>1,只有null is null才爲真,其餘都爲假
7.6.2.10.in / not in
在集合以內,0表示假,1表示真
select 5 in (3,5,34,55) =>1
7.6.3.mysql比較運算符和函數
7.6.4.mysql日期時間函數
7.6.4.1.now()
返回當前的日期和時間
select now() => 2019-04-03 14:23:19
7.6.4.2.curdate()
返回當前的日期
select curdate() => 2019-04-03
7.6.4.3.curtime()
返回當前的時間
select curtime() =>14:24:04
7.6.4.4.date_add()
返回變化後的時間,interval表示間隔,前面的時間加上後面的間隔
select date_add('2014-03-12',interval 365 day) =>2015-03-12
select date_add('2014-03-12',interval 3 week) =>2014-04-02
7.6.4.5.datediff()
返回時間差,前一個時間減去後一個時間
select datediff('2013-03-12','2014-03-12') =>-365
7.6.4.6.date_fomat()
格式化時間
select date_format('2014-03-12','%m/%d/%Y') =>03/12/2014
經常使用參數格式
%a 縮寫星期名
%b 縮寫月名
%c 月,數值
%D 帶有英文前綴的月中的天
%d 月的天,數值(00-31)
%e 月的天,數值(0-31)
%f 微秒
%H 小時 (00-23)
%h 小時 (01-12)
%I 小時 (01-12)
%i 分鐘,數值(00-59)
%j 年的天 (001-366)
%k 小時 (0-23)
%l 小時 (1-12)
%M 月名
%m 月,數值(00-12)
%p AM 或 PM
%r 時間,12-小時(hh:mm:ss AM 或 PM)
%S 秒(00-59)
%s 秒(00-59)
%T 時間, 24-小時 (hh:mm:ss)
%U 周 (00-53) 星期日是一週的第一天
%u 周 (00-53) 星期一是一週的第一天
%V 周 (01-53) 星期日是一週的第一天,與 %X 使用
%v 周 (01-53) 星期一是一週的第一天,與 %x 使用
%W 星期名
%w 周的天 (0=星期日, 6=星期六)
%X 年,其中的星期日是周的第一天,4 位,與 %V 使用
%x 年,其中的星期一是周的第一天,4 位,與 %v 使用
%Y 年,4 位
%y 年,2 位
7.6.5.mysql信息函數
7.6.5.1.connection_id()
返回鏈接ID
select connection_id() =>46
7.6.5.2.database()
返回當前正在使用的數據庫
select database(); =>xiong
7.6.5.3.last_insert_id()
返回最後插入的記錄的id,注意表中必須有id,且是primary key和auto_increment,另外若是同時插入多條記錄,那麼返回的Id爲最早插入的記錄的Id,而不是最後的
select last_insert_id(); =>26
7.6.5.4.user()
返回當前的用戶
select user();
7.6.5.5.version()
使用MySQL的版本
select version();
7.6.6.mysql聚合函數
7.6.6.1.AVG()
平均值
select avg(age) from test1;
7.6.6.2.COUNT()
總計數
select count(*) from test1;
7.6.6.3.MAX()
最大值
select max(age) from test1;
7.6.6.4.MIN()
最小值
select min(age) from test1;
7.6.6.5.SUM()
求和
select sum(age) from test1;
7.6.7.mysql加密函數
MD5()
信息摘要算法,web頁面作準備時經常使用
PASSWORD()
set password = password('newPassword') 用來更改密碼
如咱們使用test帳號登陸進入mysql
而後使用set password = password(‘1111111’);來修改test帳號的密碼
而後使用密碼爲111111的進行登陸
8.1.什麼是存儲過程
首先咱們先來了解下MySQL中執行SQL語句的一個過程,當輸入SQL命令後,MySQL引擎會對SQL命令進行分析,看SQL命令語法是否正確,若是正確,那麼繼續對SQL命令進行編譯,編譯成可識別的命令後執行命令,將執行的結果返回給客戶端。
1.若是咱們須要進行一些複雜的邏輯功能時,咱們每次都須要手動編寫這個比較複雜的SQL語句(每次編寫代碼耗時費勁)
2.在執行上面咱們說的這個複雜的語句時,就會在MySQL中執行SQL語句的方式一步一步的進行分析和編譯(執行效率不高)
爲了解決上面兩個問題,因此咱們引入了存儲過程。
存儲過程是SQL語句和控制語句的預編譯集合,以一個名稱存儲並做爲一個單元處理,(能夠理解爲,存儲過程實際上就是SQL語句與控制語句被預編譯後存儲的結果),是一組SQL語句集,功能強大,能夠實現一些比較複雜的邏輯功能,相似於JAVA語言中的方法。
存儲過程跟觸發器有點相似,都是一組SQL集,可是存儲過程是主動調用的,且功能比觸發器更增強大,觸發器是某件事觸發後自動調用;
早期的MySQL沒有存儲過程(Stored Procedure)語言,這是對習慣於企業級數據庫的程序員的最大限制。不過在MySQL 5.0之後的版本中,MySQL也開始支持存儲過程。
8.2.存儲過程的特色
加強SQL語句的功能和靈活性:能夠經過控制語句對流程進行控制和判斷,有輸入輸出參數,能夠聲明變量,有if/else, case,while等控制語句,經過編寫存儲過程,能夠實現複雜的邏輯功能;
函數的廣泛特性:模塊化,封裝,代碼複用;
實現較快的執行速度:客戶端第一次調用存儲過程時,MySQL引擎會對其進行語法分析、編譯等操做,而後將編譯結果存儲到內存中,因此第一次和以前的效率同樣,然而之後會直接調用內存中的編譯結果,效率提升。
減小網絡流量:例如刪除一個記錄,咱們本來要輸入DELETE FROM xx WHERE ...; 要傳輸的字符較多,若是寫成存儲過程,就只要調用存儲過程的名字和相應參數就行,傳輸的字符數量較少,因此減小了網絡流量
8.3.存儲過程弊端
1.不一樣數據庫,語法差異很大,移植困難,換了數據庫,須要從新編寫;
2.很差管理,把過多業務邏輯寫在存儲過程很差維護,不利於分層管理,容易混亂,通常存儲過程適用於個別對性能要求較高的業務,其它的必要性不是很大;
8.4.建立一個簡單的存儲過程
語法:
CREATE PROCEDURE 過程名([[IN|OUT|INOUT] 參數名 數據類型[,[IN|OUT|INOUT] 參數名 數據類型…]]) [特性 ...] 過程體,過程體的開始與結束使用BEGIN與END進行標識。
MySQL存儲過程的參數用在存儲過程的定義,共有三種參數類型,in,out,inout:
1.in輸入參數:表示該參數的值必須在調用存儲過程時指定並傳入存儲過程當中,在存儲過程當中修改該參數的值不會被返回,默認狀況下存儲過程的參數的類型就爲in類型的;
2.out輸出參數:該參數在調用存儲過程時須要被指定(可是參數的值並無真正的傳入到存儲過程當中),該參數可在存儲過程內部被改變,並會被返回;
3.inout輸入輸出參數:至關於in和out的結合,調用時指定,而且可被改變和返回;
8.4.1.in參數實例
delimiter //
create procedure in_par(in a int)
begin
select a;
set a = 10;
select a;
end
//
delimiter ;
set @b = 3;
call in_par(@b);
select @b;
調用的結果:
從這個例子咱們能夠看出:
in類型的參數確實被傳入到了存儲過程當中,因此在存儲過程當中第一個select a;返回的結果就是傳入的參數的值3,在存儲過程當中修改了a的值,因此第二個select a;返回的就是修改的值10;由於in類型的參數即便在存儲過程當中修改了也不會返回的,因此在調用存儲過程後的select @b返回的結果仍是3,並非被存儲過程修改的。
8.4.2.out參數實例
delimiter //
create procedure out_par(out a int)
begin
select a;
set a = 10;
select a;
end
//
delimiter ;
set @b = 3;
call out_par(@b);
select @b;
調用結果:
從上面的實例咱們能夠看出:
out類型的參數的值實際上並無傳入到存儲過程當中去,因此在存儲過程當中的第一個select a;返回的值是NULL,而在存儲過程當中使用set a = 10修改了變量a的值,因此在存儲過程當中的第二個select a;返回的結果就是10,由於out類型的參數實際上會被存儲過程修改並返回,因此在調用存儲過程後的select @b返回的就是被存儲過程修改了後的值10
8.4.3.inout參數例子
#存儲過程INOUT參數
delimiter//
create procedure inout_par(inout a int)
begin
select a;
set a = 10;
select a;
end
//
delimiter ;
set @b = 3;
call inout_par(@b);
select @b;
調用結果:
從上面的例子咱們能夠看出:
inout參數就至關於in和out的結合,因此在存儲過程當中,第一個select a;返回的結果就是傳入進去的值3,第二個select a;返回的就是修改後的值10,由於也結合了out參數類型的,因此第三個select @b返回的就是被存儲過程修改後的值10
8.5.存儲過程當中的控制語句
8.5.1.變量做用域
內部變量在其做用域範圍內享有更高的優先權,當執行到end時,內部變量消失,再也不可見了,在存儲過程外再也找不到這個內部變量,可是能夠經過out參數或者將其值指派給會話變量來保存其值。
#變量做用域
delimiter //
create procedure proc()
begin
declare x1 varchar(5) default 'outer';
begin
declare x1 varchar(5) default 'inner';
select x1;
end;
select x1;
end;
//
delimiter ;
#調用
call proc();
執行結果:
8.5.2.條件語句
8.5.2.1.if-then-else
#條件語句if-then-else
drop procedure if exists proc3;
delimiter //
create procedure proc3(in parameter int)
begin
declare var int;
set var=parameter+1;
if var=0 then
insert into t values (17);
end if ;
if parameter=0 then
update t set s1=s1+1;
else
update t set s1=s1+2;
end if ;
end ;
//
delimiter ;
8.5.2.2.case-when-then-else
delimiter //
create procedure proc4 (in parameter int)
begin
declare var int;
set var=parameter+1;
case var
when 0 then
insert into t values (17);
when 1 then
insert into t values (18);
else
insert into t values (19);
end case ;
end ;
//
delimiter ;
8.5.3.循環語句
8.5.3.1.while-do…end-while
delimiter //
create procedure proc5()
begin
declare var int;
set var=0;
while var<6 do
insert into t values (var);
set var=var+1;
end while ;
end;
//
delimiter ;
call proc5();
8.6.存儲過程的查看
8.6.1.show procedure status where db = ‘db_name’
查看某一個數據庫下建立的存儲過程
8.6.2.show create procedure pro_name
主要用於查看存儲過程的建立結構
8.7.存儲過程的刪除
8.7.1.drop procedure pro_name1,pro_name2
可支持同時刪除多個存儲過程
9.1.什麼是觸發器
觸發器(trigger):監視某種狀況,並觸發某種操做,它是提供給程序員和數據分析員來保證數據完整性的一種方法,它是與表事件相關的特殊的存儲過程,它的執行不是由程序調用,也不是手工啓動,而是由事件來觸發,例如當對一個表進行操做( insert,delete, update)時就會激活它執行。簡單的說,就是一張表發生了某件事(插入、刪除、更新操做)後,自動觸發了預先編寫好的若干條SQL語句的執行。
觸發器是由事件來觸發某個操做,這些事件包括insert語句、update語句和delete語句。當數據庫系統執行這些事件時,會激活觸發器執行相應操做。MySQL從5.0.2開始支持觸發器。
從這種意義上講觸發器是一個特殊的存儲過程。
觸發器常常用於增強數據的完整性約束和業務規則等。 觸發器建立語法四要素:
1.監視地點(table)
2.監視事件(insert/update/delete)
3.觸發時間(after/before)
4.觸發事件(insert/update/delete)
觸發器基本語法以下所示:
create trigger trigger_name trigger_time trigger_event
on tb_name for each row trigger_stmt
其中:trigger_time是觸發器的觸發時間,能夠爲before(在檢查約束前觸發)或after(在檢查約束後觸發);trigger_event是觸發器的觸發事件,包括insert、update和delete;能夠使用old和new來引用觸發器中發生變化的記錄內容;new表示當觸發插入和更新事件時可用,咱們能夠簡單的認爲插入或更新的數據對於表來講就是new的;new就指向的是被操做的記錄,old表示當觸發刪除和更新事件時可用,簡單的認爲刪除或更新的數據對於表來講就是old的,old指向的是被操做的記錄;(可結合示例理解)。trigger_stmt爲SQL語句體。
9.2.特色及做用
9.2.1.特色
觸發事件的操做和觸發器裏的SQL語句是一個事務操做,具備原子性,要麼所有執行,要麼都不執行。
MySQL中insert,update,delete三種事件支持觸發器。
建立觸發器每一個表同類事件有且僅有一個對應觸發器,也就是說對同一個表相同觸發時間的相同觸發事件,只能定義一個觸發器。
只有表才支持觸發器,視圖不支持(臨時表也不支持)。
觸發器按每一個表每一個事件每次的定義,每一個表每一個事件每次只容許一個觸發器;所以每一個表最多支持6個觸發器(每條insert、update和delete的以前和以後),單一觸發器不能與多個事件或多個表關聯。
9.2.2.做用
保證數據的完整性,起到約束的做用。
9.3.觸發器的查看
9.3.1.查看全部觸發器
show triggers;
9.3.2.查看某個具體的觸發器
show create trigger trigger_name;
9.4.觸發器的刪除
drop trigger trigger_name
9.5.實例
9.5.1.插入語句的insert觸發器
建立一個學生表student,其中id爲主鍵,且自增
插入具體的數據後查詢數據以下
建立一個成績表cj,number爲主鍵,且自增
該成績表目前沒有值,先須要設計一個觸發器,當增長新的學生時,須要在成績表中插入對應的學生信息,至於具體score_math、score_chinese、score_english後面由老師打分更新便可。
那麼,如何設計觸發器呢?
1.首先它是一個插入Insert觸發器,是創建在表student上的;
2.而後觸發時間是after,插入後的事件;
3.事件內容是插入成績表,主須要插入學生的學號和姓名,number爲自增,而成績目前不須要。
注意:new表示student中新插入的值,即新插入時的那條記錄,因此new.id表示的就是新插入student中的id的值,new.name表示新插入student中的name的值。
具體以下:
然我咱們就能夠驗證了
首先咱們能夠查看到表cj是無數據的
在student表中插入一條記錄insert into student values(null,’F’,123456,’2019-11.17);
咱們能夠看到表student已經新增了一條記錄
而後咱們再去看cj表時,已經經過觸發器新增了一條數據,獲取的id和name恰好就是新增記錄中的id和name
9.5.2.更新語句的更新觸發器
咱們一樣按上面建立的student和cj表作示例。當對錶student中的記錄進行更新後,相應的也要對錶cj中的記錄進行更新。
建立一個更新觸發器
咱們將最後一條記錄的name更新爲xiong
再次查看錶student時,最後一條記錄已經被更新
而後咱們在看錶cj時,一樣su_name一樣也作了更新操做
9.5.3.刪除語句的刪除觸發器
咱們一樣以上面的student和cj表做爲示例表,當刪除了表student中的一條數據後,也相應的要將表cj中對應的記錄也刪除掉。
建立一個刪除觸發器,須要注意的是,由於是刪除操做,因此須要使用的是old,由於是對之前的記錄進行處理
而後咱們刪除最後一條記錄試試
而後咱們再看錶cj時,已經刪除了對應的id=7,name=’xiong’的記錄了,因此表中沒有數據了
9.6.弊端
增長程序的複雜度,有些業務邏輯在代碼中處理,有些業務邏輯用觸發器處理,會使後期維護變得困難;
MySQL Trigger沒有很好的調試、管理環境,難於在各類系統環境下測試,測試比MySQL存儲過程要難,因此建議在生成環境下,儘可能用存儲過程來代替MySQL觸發器。
10.1.什麼是視圖
通俗的講,視圖就是一條select語句執行後返回的結果集,是一個虛擬表,視圖自己沒有數據,行和列數據來自由定義視圖的查詢所引用的表,而且在引用視圖時動態執行相應的select語句完成得到相應的數據
10.2.視圖的特性
1 視圖的列能夠來自不一樣的表,是表的抽象和邏輯意義上創建的關係。
2 視圖是由基本表(實表)產生的表(虛表)。
3 視圖的創建和刪除不影響基本表。
4 對視圖的內容更新(添加、刪除、修改)直接影響基本表。
5 當視圖來自多個基本表時,對數據的修改是有條件的(具體能夠看下面)
10.3.視圖的做用
一、 視圖能簡化用戶操做
關鍵信息來源於多個複雜關聯表,能夠建立視圖提取咱們須要的信息,簡化操做;
二、視圖可以對機密數據提供安全保護
數據庫受權命令不能限定到特定行和特定列,可是經過合理建立視圖,能夠把權限限定到行列級別。
10.4.使用場合
1.儘可能使用視圖完成讀操做
2.能夠隱藏一些數據,不但願用戶訪問表中某些含敏感信息的列,好比salary...
3.關鍵信息來源於多個複雜關聯表,能夠建立視圖提取咱們須要的信息,簡化操做
4.若是使用視圖,則須要注意,對視圖的修改,也是對基表的修改,會即時生效
5.刪除視圖時,不會銷燬實體表內的數據
10.5.視圖基本操做
10.5.1.視圖建立
create view view_name as select ... from ...
示例1:
create view v_student as select * from student;
10.5.2.視圖修改
10.5.2.1.視圖的修改
create or replace view_name as select ... from ...
示例
create or replace view v_student as select * from student where id <= 4;
10.5.2.2.視圖數據的變動
更新update
插入數據insert
須要注意的是,對於視圖數據的操做是有條件的,那究竟何時能夠操做視圖的數據呢?
1.視圖與表是一對一關係:
若是沒有其它約束(這個約束就是視圖沒有存在的其餘基本表字段都不是not null的狀況)能夠修改,由於對視圖的修改也會影響到原表,因此對視圖進行修改時,若是原表其餘沒在視圖中的字段沒有not null約束時,就能夠對視圖進行修改操做。
2.視圖與表是一對多關係:
若是修改視圖的操做只會涉及到某一個表的數據時,這時是能夠對視圖進行修改的,若是修改時會涉及到兩個表的數據,那麼就不能對視圖進行修改。
好比咱們如今的表爲:學生表user,課程表course,學生課程表user_course
建立的視圖爲,將三個表作鏈接查詢,方便查看每一個學生所學的課程,好比咱們能夠查看小張上的全部課程信息
像如下就能夠修改視圖數據成功:
update view_user_course set coursename='JAVA' where id=1; 【只更新了課程表course】
update view_user_course set username='test2' where id=3; 【只更新了學生表user】
像如下就不能修改視圖數據成功:
delete from view_user_course where id=3; 【同時修改學生表user和課程表course】
insert into view_user_course(username, coursename) VALUES('2','3'); 【一樣會修改學生表user和課程表course的數據】
10.5.3.視圖查看
show tables; 查看當前數據庫下的全部表,包括了基本表、視圖、臨時表
show full tables where table_type like ‘view’; 查看當前數據庫下的全部視圖
查看視圖詳情與查看錶同樣
desc 視圖名
show fields from 視圖名
show columns from 視圖名
10.5.4.視圖刪除
drop view view_name
10.6.其它
10.6.1.with check option
通常狀況下,若是在建立視圖的時候指定了「with check option」,那麼更新數據時不能插入或更新不符合視圖限制條件的記錄,with check option對於沒有where條件的視圖不起做用。
插入後的數據,經過視圖可以查詢出來就符合with check option,不然就不符合;
首先視圖只操做它能夠查詢出來的數據,對於它查詢不出的數據,即便基表有,也不能夠經過視圖來操做。
1.對於update,有with check option,要保證update後,數據要被視圖查詢出來
2.對於delete,有無with check option都同樣
3.對於insert,有with check option,要保證insert後,數據要被視圖查詢出來
10.6.2.視圖算法
視圖算法是對視圖以及外部查詢視圖的select語句的一種解析方式,簡單的說就是視圖的select語句和外部的SQL語句的執行策略。
視圖算法分爲三種:
undefined :未定義(默認的)這不是一種實際算法,是一種推卸責任的算法,就是告訴系統沒有定義算法,讓系統本身選擇。
temptable:臨時表算法.系統先執行視圖select語句,後執行外部select查詢語句
marge : 合併算法.系統先將視圖對應的select語句與外部查詢視圖的select語句進行合併,而後執行(效率高:常態),系統在undefined條件下優先選擇marge
create algorithm = 指定算法 view 視圖名字 as select 語句
11 其餘
11.1.autocommit
如何理解autocommit:
MySQL默認操做模式就是autocommit自動提交模式。這就表示除非顯式地開始一個事務,不然每一個查詢都被當作一個單獨的事務自動執行。咱們能夠經過設置autocommit的值改變是不是自動提交autocommit模式
查看數據庫中autocommit變量的默認值:select @@AUTOCOMMIT【咱們能夠從中看出,在mysql中,autocommit默認是開啓的】
設置autocommit:set @@AUTOCOMMIT = 0;
當autocommit爲1即爲開啓的時候,系統會自動向數據庫提交結果,即自動執行了commit操做,若是用戶但願經過控制MySQL自動提交參數,能夠更改提交模式,這一更改過程是經過設置AUTOCOMMIT變量來實現,下面用實例來演示相關的特色:
下面開啓了兩個session,分別是A,B
1.兩個session的autocommit都是1,即爲默認
在這種狀況下,A對某一個數據表進行增刪改操做,不須要執行commit操做,在B中均可以查詢到修改後的內容,一樣在B作任何修改的內容,不須要執行commit操做,仍然能夠在A中看到修改的內容:
A:查看autocommit
B:查看autocommit
A:查看錶test1
B:查看錶test1
A:刪除id爲13的數據
B:查詢test1表【咱們能夠看到查詢的結果和A中是如出一轍的的】
總結:
當兩個都爲默認,即atuocommit都爲1時,由於都會自動提交,因此每一個session執行後就會自動執行commit操做,因此其餘的session就能看到修改後的內容
2.A的autocommit爲0,B的autocommit爲1
A:將autocommit設置爲0
B:不修改autocommit,保持默認值爲1
A:查看test1表的數據
B:查看test1表的數據
A:插入一條數據,並查看錶test1數據
B:查看錶test1表數據【咱們能夠看出在B中,沒有查看到新增的數據】
A:使用commit提交,並查看數據
B:查看錶test1表數據【咱們能夠看到修改後的數據了,由於A使用了commit操做】
總結:
總的來講,若是A不是自動提交,B是自動提交,那麼A要提交後B才能看到,若是A是自動提交,B 不是自動提交,那麼B要看到也要使用commit才能看到,若是A和B都是非自動提交,那麼兩個都必需要使用commit操做才能讓對方看到的內容相同。
總的就是,不是自動提交的,要使用commit命令後才能看到別人修改的,或這讓本身修改的讓別人看到。
MySQL中默認的都是默認提交的,但當咱們顯示的使用了start transaction或者begin時,咱們就要使用commit來提交纔會讓其餘的session看到咱們修改的內容。
11.2.MySQL僞事務
在MySQL中,InnoDB和BDB類型表能夠支持事務處理,可是MySQL中MyISAM類型表並不能支持事務處理,對於某些應用該類型的數據表,用戶能夠選擇應用表鎖定來替代事務。這種引用表鎖定來替代事務的事件被稱做僞事務。使用表鎖定來鎖定表的操做,能夠增強非事務表在執行過程的安全性和穩定性。
在MySQL的MyISAM類型數據表中,並不支持COMMIT(提交)和ROLLBACK(回滾)命令。當用戶對數據庫執行插入、刪除、更新等操做時,這些變化的數據都被馬上保存在磁盤中。這樣,在多用戶環境中,會致使諸多問題。爲了不同一時間有多個用戶對數據庫中指定表進行操做,能夠應用表鎖定來避免在用戶操做數據表過程當中受到干擾。當且僅當該用戶釋放表的操做鎖定後,其餘用戶才能夠訪問這些修改後的數據表。
設置表鎖定代替事務基本步驟以下:
(1)爲指定數據表添加鎖定。其語法以下:
LOCK TABLES table_name1 lock_type1,table_name2 lock_type2
其中,table_name爲被鎖定的表名,lock_type爲鎖定類型,該類型包括以讀方式(READ)【能夠容許其餘session讀,但不能作修改操做】鎖定表,以寫方式(WRITE)【不容許其餘session作任何操做】鎖定表。
(2)用戶執行數據表的操做,能夠添加、刪除或者更改部分數據。
(3)用戶完成對鎖定數據表的操做後,須要對該表進行解鎖操做,釋放該表的鎖定狀態。其語法以下:
UNLOCK TABLES
實例:
首先咱們能夠看到咱們當前的表test1的引擎是myisam
SessionA:鎖定表test1
sessionB:讀取表test1【一直在等待中】
sessionA:解鎖表
sessionB:能夠查看到表test1的數據了
注意:若是sessionA鎖定表時用的是lock table tb_name read,那麼sessionB是能夠讀取數據的,只是sessionB不能進行增刪改操做。
11.2.1.總結
應用表鎖實現僞事務
經過使用表鎖定對MyISAM表進行鎖定操做,以此過程來代替事務型表InnoDB,即應用表鎖定來實現僞事務。實現僞事務的通常步驟以下:
(1)對數據庫中的數據表進行鎖定操做,能夠對多個表作不一樣的方式鎖定,其代碼格式以下:
LOCK TABLE table_name1 lock_type1,table_name2 lock_type2,……
(2)執行數據庫操做,向鎖定的數據表中執行添加、刪除、修改操等操做。
如前面提到的INSERT、UPDATE、DELETE等操做。用戶能夠對鎖定的數據表執行上述操做,在執行過程當中,該僞事務所產生的結果是不會被其餘用戶更改的。
(3)釋放鎖定的數據表,以便讓正在隊列中等待查看或操做的其餘用戶能夠瀏覽數據表中的數據或對操做表執行各類數據的操做。
UNLOCK TABLES
若是存在其餘會話要求訪問已鎖定的多個表格,則該會話必須被迫等待當前鎖定用戶釋放鎖定表。才容許其餘會話訪問該數據表,表鎖定使不一樣會話執行的數據庫操做彼此獨立。應用數據表鎖定方式能夠使不支持事務類型的表實現僞事務
11.3.MySQL執行計劃
參考地址:https://www.cnblogs.com/zping/p/5368860.html
11.4.建立臨時表
建立臨時表與建立通常的表是差很少,只是使用了temporary關鍵字,另外須要注意的幾點:
1.MySQL版本低於 3.23版本就沒法使用MySQL的臨時表
2.臨時表只在當前鏈接可見,當關閉鏈接時,Mysql會自動刪除表並釋放全部空間
3.若是使用了其餘MySQL客戶端程序鏈接MySQL數據庫服務器來建立臨時表,那麼只有在關閉客戶端程序時纔會銷燬臨時表,固然也能夠手動銷燬
4.使用show tables是看不到臨時表的
5.臨時表的刪除仍然使用:drop table tb_name
create temporary table tb_name(
id tinyint unsigned not null,
name varchar(20) not null,
age int unsigned not null
);
11.5.複製表
表的複製,這裏主要講解了三種複製的方法,另外還有一種方法就是,首先查看須要複製表的結構(show create table 須要複製表的表名),而後複製後從新將表的名字改成複製表的名字就建立了表結構,在而後使用insert into 複製表的表名 (select * from 須要複製表的表名)
11.5.1.CREATE TABLE tab_new [AS] SELECT * FROM tab_old【複製表的部分結構和全部內容】
實例:
create table xiong as select * from test1; 使用這種方式闖進一個test1表的複製表xiong
show create table test1; 查看錶test1的結構
查看複製表xiong的結構
查看錶test1的內容:
查看錶xiong的內容:
將表test1的結果和複製表xiong的結構放在一塊兒對比咱們能夠看出:複製表中並無複製到primary key ,auto_increment,index等
總結:
這種方法能夠複製表的內容和表的結構,可是不能複製表的結構中的主鍵,索引,外鍵,auto_increment等,因此複製以後須要本身進行從新加入主鍵,index等纔會是完整的將表複製。
11.5.2.CREATE TABLE tab_new AS SELECT * FORM tab_old WHERE 1=2【複製表的部分結構】
這個方法和上面同樣的,只是使用where 1=2不成立的條件,因此就不會複製到表的內容,這裏就再也不作實例的講解
11.5.3.CREATE TABLE tab_new LIKE tab_old【複製表的全部結構】
實例:
create table ying like test1 使用如上方法建立表test1的複製表ying
查看錶test1的結構
查看錶ying的結構:
查看錶test1的數據:
查看錶ying的數據:
總結:
使用這種方法能夠徹底複製表的結構,包括主鍵、外鍵、auto_increment等,可是這種方法能複製表的內容,因此若是須要徹底的複製表,咱們還能夠使用以下方法來將數據複製進去。
insert into ying (select * from test1);
select * from ying; 查看錶ying的數據就是和表test1的同樣了
11.6.重複數據
咱們能夠在 MySQL 數據表中設置指定的字段爲 PRIMARY KEY(主鍵) 或者 UNIQUE(惟一) 索引來保證數據的惟一性。其中主鍵確保字段惟一且不能爲null,而惟一鍵確保字段惟一,可是能夠爲null。
11.6.1.INSERT IGNORE INTO
INSERT IGNORE INTO 與 INSERT INTO 的區別就是 INSERT IGNORE INTO會忽略數據庫中已經存在的該條數據,若是數據庫沒有數據,就插入新的數據,若是有數據的話就跳過這條數據(即不會插入數據)。這樣就能夠保留數據庫中已經存在數據,達到在間隙中插入數據的目的。
實例:
首先查看錶xiong的數據:
查看錶xiong的結構【咱們能夠看id是主鍵,age是惟一鍵】
使用insert ignore into方式插入一條age重複的數據【咱們能夠看到並無報錯,只是有1個warning】
再查看錶xiong的數據【咱們能夠看到忽略了插入的數據,由於表中已存在age爲23的數據】
11.6.2.REPLACE INTO
而 REPLACE INTO 若是存在 primary 或 unique 相同的記錄,則先刪除掉,再插入新記錄。
和上面的例子差很少,首先查看錶xiong的數據
再看看錶xiong的結構【咱們能夠看id是主鍵,age是惟一鍵】
而後使用 replace into 方法插入一條重複數據
查看錶xiong的數據【咱們能夠看到原來的數據id=100,age=23的數據變爲了id=104,age=23的了,這裏須要注意,由於id是主鍵且自增的,因此插入時使用null表示的是自增】
11.6.3.統計重複數據
通常狀況下,查詢重複數據:
肯定哪一列包含的值可能會重複。
在列選擇列表使用COUNT(*)列出的那些列。
在GROUP BY子句中列出的列。
HAVING子句設置重複數大於1
實例:
查看錶test1的數據:
使用如上方法對age列進行重複數據的查詢【咱們能夠看到重複的數據以下】
11.6.4.過濾重複數據
1.使用distinct關鍵字,可是須要注意的是,使用distinct關鍵字必須放在前面,另外若是後面有多個字段,則表示對多個字段進行去重,如distinct id,name表示id+name不一樣纔會被過濾
select distinct age from test1;
2.使用group by,由於使用group by同一個分組的就只會展現一條,咱們能夠看到效果和上面是差很少的
11.6.5.刪除重複數據
首先先使用上面的複製表的方法,這裏使用12.5.3的方法
create tabel ttt like tt 建立表tt的複製表ttt
insert into ttt (select * from tt group by id,age)而後向表ttt中插入tt表中不重複的數據
查看錶ttt的數據,咱們就能夠看到表ttt爲表tt中不重複的數據了
使用in 或者not in 的子查詢的注意事項
1.咱們能夠看到這兩個表x1,x2,x1的數據以下:
2.x2的數據以下:
3.咱們能夠看出x1,x2同時擁有id和number兩個字段,咱們從值也能夠看出,x1的number基本包含了x2的number,可是x2中有值爲null的,如今咱們想要查詢x1中number不包含x2的數據
4.咱們使用子查詢方法,其中過濾掉x2表中number不爲空的
5.若是咱們使用以下的子查詢,可是沒有過濾掉x2表中number爲空的數據,則查詢的結果就爲空(由於x2表中擁有了一條number爲null的數據,null不會in在任何數內,即便null 也不會in null的,因此若是不過濾number爲null的話,查詢的結果就會爲空)
6.咱們一樣能夠來看以下這個例子,咱們先在x1表中添加一條number爲null的數據
7.咱們能夠看到x1表中仍然有number爲null,x2表中仍然有number爲null的數據,而後咱們再使用以下方式查詢,查詢的結果仍然爲空。
8.再使用過濾x2表中numer爲null的數據查詢時,結果就能正確查詢出來
9.一樣咱們能夠這個例子能夠看出null 是不會in null的,查詢的結果並無number爲null的。
總結:
從上面的例子咱們能夠看出,null是不會in在任何數據內的,即便是null in null也不會成立的,因此咱們在使用in 或者not in 時,記得要把子查詢中爲null的數據過濾了,不然查詢的結果就會爲空。