漫談mysql

數據庫mysql

1.1 數據庫

1. 概念

  1. 用戶認證mysql

    • 註冊:用戶名不能重複
    • 登錄
  2. 只是經過文件操做,改變數據是很是繁瑣的linux

  3. 解決對於多臺機器多個進程操做同一份數據咱們須要本身解決併發安全問題比較麻煩ios

  4. 本身處理數據備份,容錯措施正則表達式

  5. c/s架構的操做數據文件的一個管理軟件redis

    • 解決併發問題
    • 實現用更簡單快速的方式完成數據的增刪改查
    • 提供一些容錯、高可用的機制
    • 權限的認證
  6. 數據操做算法

    1. 鏈接server
    2. 指令
  7. 專有名詞sql

    1. 數據庫管理系統(DBMS):專門用來管理數據文件,幫助用戶更簡潔的操做數據的軟件
    2. 數據(data)、文件
    3. 數據庫(database, DB):每個項目都有一個數據庫
    4. 數據庫管理員(DBA)
  8. 常見的數據庫mongodb

    • 關係型數據庫數據庫

      • Relational Database Management System:(RDBMS)是指包括相互聯繫的邏輯組織存取這些數據的一套程序 (數據庫管理系統軟件)。關係數據庫管理系統就是管理關係數據庫,並將數據邏輯組織的系統。
      1. sql server/ sqlite/ db2/ access/
      2. oracle:收費,比較嚴謹,安全性高(國企、事業單位銀行、金融行業)
      3. mysql:開源(小公司互聯網公司)
      4. 注意:sql語句通用
    • 非關係型數據庫(key:value結構)eg:快遞單號(redis、mongodb、memcache)

    • 在 WEB 應用方面,MySQL是最好的 RDBMS(關係數據庫管理系統) 應用軟件。

2. mysql的安裝

  1. win,路徑必須是全英文
  2. bin目錄
  3. my.ini文件(文件名必須是這個)
# 客戶端
[mysql]
# 設置mysql客戶端默認字符集
default-character-set=utf8 

# server端
[mysqld]
#設置3306端口
port = 3306
# 設置mysql的安裝目錄
basedir=C:\Program Files\mysql-5.6.39-winx64 
# 設置mysql數據庫的數據的存放目錄
datadir=C:\Program Files\mysql-5.6.39-winx64\data 
# 容許最大鏈接數
max_connections=200
# 服務端使用的字符集默認爲8比特編碼的latin1字符集
character-set-server=utf8mb4
# 建立新表時將使用的默認存儲引擎
default-storage-engine=INNODB
  1. 安裝路徑:不能有空格,不能有中文,不能帶着轉義特殊字符開頭的文件夾名
  2. 安裝以後發現配置有問題:再修改配置文件每每不能生效
    • 卸載以後重裝
    • mysqld remove,把全部配置、PATH修改正確
    • 重啓計算機—清空註冊表
    • 從新安裝:mysqld install

3. mysql的cs架構

# windows
mysqld install
net start mysql
#  server net stop mysql
mysql -u'用戶名' -p'密碼'
# 客戶端,能夠是python代碼也能夠是一個程序
# mysql.exe是一個客戶端
# mac
sudo mysql.server status
sudo mysql.server start/stop/restart

3.1 mysql中的用戶和權限

  • 在安裝數據庫以後,有一個最高權限的用戶root
  • mysql server端的ip 用戶名/密碼
  • Mysql -h192.168.12.87 -uroot -p123

Note1

  1. 能夠鏈接網絡上的某一個數據庫

3.2 數據庫中的概念

  • 庫、表、數據
    • 描述事物的符號記錄稱爲數據,如:一條數據data(一行數據)
    • 表就至關於文件,表中的一條記錄就至關於文件的一行內容,多條數據組成一個表
    • 數據庫即存放數據的倉庫,多個表組成一個庫
    • 通常狀況下:一個項目佔用一個或以上個庫

3.3 mysql的操做

  • sql語句(structure query language)

    • SQL : 結構化查詢語言(Structured Query Language)簡稱SQL(發音:/ˈes kjuː ˈel/ "S-Q-L"),是一種特殊目的的編程語言,是一種數據庫查詢和程序設計語言,用於存取數據以及查詢、更新和管理關係數據庫系統。
    • SQL語言主要用於存取數據、查詢數據、更新數據和管理關係數據庫系統,SQLsu語言由IBM開發。SQL語言分爲3種類型
    1. DDL語句 數據庫定義語言:數據庫,表,視圖,索引,存儲規程
    2. DML語句 數據庫操縱語言:插入數據insert,delete,update,alter
    3. DCL語句 數據庫控制語言:建立用戶。grant revoke 取消受權
# 查看當前用戶
select user(); 
# 設置密碼,password 表示密文存儲
set password for root@localhost = password('123');
# 建立用戶
create user '用戶名'@'網段.%' identified by '密碼';
# 查看用戶狀態,用戶信息都存儲在mysql中的user表中
select host,user from mysql.user;
# 查看當前庫
show databases;
# 建立文件夾henry
create database henry;
# 查看指定用戶權限
show grants for '用戶名'(@'網段.%');
# 受權 * 表示全部
grant   all(select/insert) on henry.* to '用戶名'@'ip網段.%';
# 設置當即生效
flush privileges
# 建立帳號並受權,必須有密碼
grant all on herny.* to 'henry'@'%' identified by '123';
#select, insert, update, delete, create, drop, index, alter, grant, references, reload, shutdown, process, file等14個權限

# 取消用戶權限
revoke all on test.* from 'henry'@'%';
# 刪除用戶
delete from mysql.user where host='192.168.12.%' and user='test';
drop user 'test'@'192.168.12
# 修改指定用戶密碼
update mysql.user set password=password('新密碼') where User='test' and Host='%';
  • 庫的操做
# 建立庫
create database demo;
# 查看庫
show databases;
# 刪除庫,demo
drop database demo
# 查看當前使用的庫
select database();
# 切換庫,到demo庫下
use demo;
  • 表操做(4)
# 建立表,char()默認一個字符
create table student(id int, name char(10));
# 查看當前文件夾中的表
show tables;
# 刪除表
drop table student;
# 查看錶結構
desc student;
# 刪除多個表
drop tables s2,s3,s4;
  • 操做表中數據(4)
# 數據插入
insert into student values(1, 'henry');
# 數據查看
select * from student;
# 修改數據,必須設置條件,肯定爲一條數據data
update 表 set 字段名=值 where id=2;
# 刪除數據
delete from 表 where id=1;

1.2 表的介紹

1. 存儲引擎

  • 選擇如何存儲和檢索數據的這種靈活性是MySQL爲何如此受歡迎的主要緣由。其它數據庫系統(包括大多數商業選擇)僅支持一種類型的數據存儲。
  • mysql5.6/5.7支持的存儲引擎包括InnoDBMyISAMMEMORYCSVBLACKHOLEFEDERATEDMRG_MYISAMARCHIVEPERFORMANCE_SCHEMA。其中NDBInnoDB提供事務安全表,其餘存儲引擎都是非事務安全表。

1.1 表的存儲方式(3)

  1. 方式1:MyISAM
    1. mysql5.5- 默認存儲方式
    2. 存儲的文件個數:表結構表數據索引
    3. 不支持行級鎖、事務和外鍵
  2. 方式2:InnoDB
    1. mysql5.6+ 默認存儲方式
    2. 存儲文件個數:表結構表數據
    3. 支持事務:把多句操做,變成原子操做
    4. 支持外鍵:經過外鍵(有約束)在其餘表(有約束)中查找信息
    5. 支持行級鎖(默認):髒數據(+表級鎖),支持數據併發
  3. 方式3:MEMORY
    1. 存儲在內存:表結構存儲到硬盤中, 表數據存儲到內存上
    2. 優點:增刪改查速度快
    3. 劣勢:重啓數據消失、容量有限

1.2 存儲引擎介紹

  • InnoDB
    1. 用於事務處理應用程序,支持外鍵行級鎖
    2. 若是應用對事物的完整性有比較高的要求,在併發條件下要求數據的一致性
    3. 數據操做除了插入查詢以外,還包括不少更新刪除操做,那麼InnoDB存儲引擎是比較合適的。
    4. InnoDB除了有效的下降由刪除和更新致使的鎖定,還能夠確保事務的完整提交和回滾,對於相似計費系統或者財務系統等對數據準確要求性比較高的系統都是合適的選擇。
  • MyISAM
    1. 若是應用是以讀操做插入操做爲主
    2. 只有不多的更新和刪除操做,而且對事務的完整性、併發性要求不高,那麼能夠選擇這個存儲引擎。
  • Memory
    • 將全部的數據保存在內存中,在須要快速定位記錄和其餘相似數據的環境下,能夠提供極快的訪問。Memory的缺陷是對錶的大小有限制,雖然數據庫由於異常終止的話數據能夠正常恢復,可是一旦數據庫關閉,存儲在內存中的數據都會丟失。

其餘存儲引擎

  1. InnoDB
    • MySql 5.6 版本默認的存儲引擎。InnoDB 是一個事務安全的存儲引擎,它具有提交、回滾以及崩潰恢復的功能以保護用戶數據。InnoDB 的行級別鎖定以及 Oracle 風格的一致性無鎖讀提高了它的多用戶併發數以及性能。InnoDB 將用戶數據存儲在彙集索引中以減小基於主鍵的普通查詢所帶來的 I/O 開銷。爲了保證數據的完整性,InnoDB 還支持外鍵約束
  2. MyISAM
    • MyISAM既不支持事務、也不支持外鍵、其優點是訪問速度快,可是表級別的鎖定限制了它在讀寫負載方面的性能,所以它常常應用於只讀或者以讀爲主的數據場景。
  3. Memory
    • 在內存中存儲全部數據,應用於對非關鍵數據由快速查找的場景。Memory類型的表訪問數據很是快,由於它的數據是存放在內存中的,而且默認使用HASH索引,可是一旦服務關閉,表中的數據就會丟失
  4. BLACKHOLE
    • 黑洞存儲引擎,相似於 Unix 的 /dev/null,Archive 只接收但卻並不保存數據。對這種引擎的表的查詢經常返回一個空集。這種表能夠應用於 DML 語句須要發送到從服務器,但主服務器並不會保留這種數據的備份的主從配置中。
  5. CSV
    • 它的表真的是以逗號分隔的文本文件。CSV 表容許你以 CSV 格式導入導出數據,以相同的讀和寫的格式和腳本和應用交互數據。因爲 CSV 表沒有索引,你最好是在普通操做中將數據放在 InnoDB 表裏,只有在導入或導出階段使用一下 CSV 表。
  6. NDB
    • (又名 NDBCLUSTER)——這種集羣數據引擎尤爲適合於須要最高程度的正常運行時間和可用性的應用。注意:NDB 存儲引擎在標準 MySql 5.6 版本里並不被支持。
    • MySql 集羣的版本有:基於 MySql 5.1 的 MySQL Cluster NDB 7.1;基於 MySql 5.5 的 MySQL Cluster NDB 7.2;基於 MySql 5.6 的 MySQL Cluster NDB 7.3。一樣基於 MySql 5.6 的 MySQL Cluster NDB 7.4 目前正處於研發階段。
  7. Merge
    • 容許 MySql DBA 或開發者將一系列相同的 MyISAM 表進行分組,並把它們做爲一個對象進行引用。適用於超大規模數據場景,如數據倉庫。
  8. Federated
    • 提供了從多個物理機上聯接不一樣的 MySql 服務器來建立一個邏輯數據庫的能力。適用於分佈式或者數據市場的場景。
  9. Example
    • 這種存儲引擎用以保存闡明如何開始寫新的存儲引擎的 MySql 源碼的例子。它主要針對於有興趣的開發人員。這種存儲引擎就是一個啥事也不作的 "存根"。你可使用這種引擎建立表,可是你沒法向其保存任何數據,也沒法從它們檢索任何索引。

1.3 查看mysql全部的配置

# 查看與存儲引擎相關配置
show variables like '%engine%';
show variables like "default_storage_engine";
# 查看當前數據庫支持的存儲引擎
show engines \g
show engines;
# 修改已經存在表的存儲引擎
alter table 表名 engine = innodb;
# 查看與編碼相關的配置
show variables like '%chara%';
# 查看
show variables like '%關鍵字%';
  • 指定存儲引擎
# 建立表
create table t1(id int, name char(10)) engine=innodb;
# 查看錶的結構,包括存儲引擎和編碼 \G 格式化輸出,帶   \G 不能使用分號
show create table t1 \G
# 只查看錶字段基礎信息
describle t1;

t1.frm frame 表結構
t1.ibd innoDB 存儲引擎
# 指定engine爲myisam
create table t2(id int, name char(10)) engine=MyISAM;

t2.frm 表結構
t2.MYD 數據
t2.MYI 索引
# 指定engine爲memory
create table t2(id int, name char(10)) engine=memory;

t2. 數據

2. mysql數據類型

# 語法:
create table 表名(
字段名1 類型[(寬度) 約束條件],
字段名2 類型[(寬度) 約束條件],
字段名3 類型[(寬度) 約束條件]);

# 注意:
1. 在同一張表中,字段名是不能相同
2. 寬度和約束條件可選
3. 字段名和類型是必須的
  • 數值:
    • TINYINT(1byte),SMALLINT(2byte),MEDIUMINT(4byte),INT(4byte),BIGINT(8byte)
  • 日期時間
  • 字符
  • ENUMSET類型

2.1數值

  1. MySQL支持全部標準SQL數值數據類型。這些類型包括嚴格數值數據類型(INTEGERSMALLINTDECIMALNUMERIC),以及近似數值數據類型(FLOATREALDOUBLE PRECISION)。
  2. 關鍵字INT是INTEGER的同義詞,關鍵字DEC是DECIMAL的同義詞。
  3. MySQL支持的整數類型有TINYINTMEDIUMINTBIGINT
  4. 對於小數的表示,MYSQL分爲兩種方式浮點數和定點數。浮點數包括float(單精度)和double(雙精度),而定點數只有decimal一種,在mysql中以字符串的形式存放,比浮點數更精確,適合用來表示貨幣等精度高的數據。
  5. BIT數據類型保存位字段值,而且支持MyISAM、MEMORY、InnoDB和BDB表。
  • 整數(int)
# 建立無符號int型表
create table t3(id1 int, id2 int unsigned);
  • 小數(float/double)
# 一共有5位,小數2位
float(5, 2)/ double(5, 2)
# 建立表
create tables t4(f1 float(5,2), double(5,2));
# 不指定長度,單精度和雙精度
create tables t4(f1 float, double);
# decimal精度,默認存儲(10,0)整數
create table t5(d1 decimal, d2 decimal(25, 20));
# decimal內部存儲是按照字符串存的

Note2(4)

  1. 默認int類型有符號
  2. int類型數據範圍不被寬度約束
  3. 5.6版只能約束數字的顯示寬度,5.7不受限制
  4. 5.6版插入數據超過最大長度會默認顯示最大值,5.7版直接會提示:Out of range value

2.2 時間和日期(5)

  1. date:年月日
  2. time:時分秒
  3. year:年份值
  4. datetime:年月日時分秒
  5. timestamp:年月日時分秒
    • 1970-01-01 00:00:00/2038結束時間是第 2147483647 秒,北京時間 2038-1-19 11:14:07,格林尼治時間 2038年1月19日 凌晨 03:14:07
# 建立表
create table t6(d1 date, y year, ts timestamp);
insert into t6(now(), now(), now());
# 指定傳y,datetime默認爲更新時間
insert into t6(y) values(2019);
# 指定datetime更新方式
create table t6(d1 date, y year, 
                dt datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
# 可使用字符串,純數字
# 5.7版本,插入參數不全,會報錯,5.6版不會

2.3 字符串

  1. 字符串類型指CHARVARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUMSET。該節描述了這些類型如何工做以及如何在查詢中使用這些類型。
  2. BINARY 和 VARBINARY 相似於 CHAR 和 VARCHAR,不一樣的是它們包含二進制字符串而不要非二進制字符串。也就是說,它們包含字節字符串而不是字符字符串。這說明它們沒有字符集,而且排序和比較基於列值字節的數值值。
  3. BLOB 是一個二進制大對象,能夠容納可變數量的數據。有 4 種 BLOB 類型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它們區別在於可容納存儲範圍不一樣。
  4. 有 4 種 TEXT 類型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。對應的這 4 種 BLOB 類型,可存儲的最大長度不一樣,可根據實際狀況選擇。
  • char:定長字符串(3)
    • 補齊指定長度的
    • 長度變化小的狀況使用、浪費空間,存儲效率較高
    • 用戶名、密碼、身份證、手機號
  • varchar:變長字符串(3)
    • 存儲輸入長度的+1 eg.alex 則存儲alex4
    • 節省空間、存儲效率s相對低
    • 評論、微博、說說、微信狀態
create table t7(name1 char(5), name2 varchar(5));
# 分別存儲 'echo ' 和 'echo4'
insert into t7 values('echo', 'echo')
select concat(name1, '---') from t7;
select concat(name2, '---') from t7;

2.4 enum和set類型

  1. ENUM中文名稱叫枚舉類型,它的值範圍須要在建立表時經過枚舉方式顯示。ENUM只容許從值集合中選取單個值,而不能一次取多個值
  2. SET和ENUM很是類似,也是一個字符串對象,裏面能夠包含0-64個成員。根據成員的不一樣,存儲上也有所不一樣。set類型能夠容許值集合中任意選擇1或多個元素進行組合。對超出範圍的內容將不容許注入,而對重複的值將進行自動去重。
  • en ENUM('male', 'female'):單選框
  • s set(''):多選框
  • 5.6版本取交集,5.7版本插入的數據必須和指定數據一致,否則會報錯
create table t8(name char(12), 
                gender ENUM('male', 'female'),
               hobby set('play', 'drink', 'eat'));

3. mysql工做流程

sql工做流程

  • MySQL架構總共四層,在上圖中以虛線做爲劃分。
    1. 最上層的服務並非MySQL獨有的,大多數給予網絡的客戶端/服務器的工具或者服務都有相似的架構。好比:鏈接處理受權認證安全等
    2. 第二層的架構包括大多數的MySQL的核心服務。包括:查詢解析、分析、優化、緩存以及全部的內置函數(例如:日期、時間、數學和加密函數)。同時,全部的跨存儲引擎的功能都在這一層實現:存儲過程觸發器視圖等
    3. 第三層包含了存儲引擎存儲引擎負責MySQL中數據的存儲和提取。服務器經過API和存儲引擎進行通訊。這些接口屏蔽了不一樣存儲引擎之間的差別,使得這些差別對上層的查詢過程透明化。存儲引擎API包含十幾個底層函數,用於執行「開始一個事務」等操做。但存儲引擎通常不會去解析SQL(InnoDB會解析外鍵定義,由於其自己沒有實現該功能),不一樣存儲引擎之間也不會相互通訊,而只是簡單的響應上層的服務器請求。
    4. 第四層包含了文件系統,全部的表結構和數據以及用戶操做的日誌最終仍是以文件的形式存儲在硬盤上。

1.3 表的完整性約束

1. 約束

  • unsigned:設置無符號
  1. NOT NULL :非空約束,指定某列不能爲空;
  2. DEFAULT:默認值,當同一數據大量出現時使用;
  3. UNIQUE : 惟一約束,指定某列或者幾列組合不能重;
  4. PRIMARY KEY主鍵,指定該列的值能夠惟一地標識該列記;
  5. FOREIGN KEY :外鍵,指定該行記錄從屬於主表中的一條記錄,主要用於參照完整性。

1.1 not null

  • 非空
create table t1(id int not null,
               name char(12) not null,
               age int);
insert into t1(id, name) values(1, 'henry');

1.2 default

  • 默認值,建立列時能夠指定默認值,當插入數據時若是未主動設置,則自動添加默認值
create table t2(id int not null,
               name char(12) not null,
               gender enum('male', 'female') not null default 'male'
               );       
insert into t2(id, name) values(1, 'henry');

1.3 unique

  • 不重複(key UNI),全部的非空數據不重複
  • 惟一約束,指定某列或者幾列組合不能重複
create table t3(id int unique,
               username char(12) not null unique,
               pwd char(18)
               );
  • 聯合惟一(key MUL)
create table t4(id int not null unique,
               ip char(15),
               server char(10),
               port int,
               unique(ip, port))  # 聯合惟一,不能同時重複

1.4 auto_increment

  1. 自增(只能用於數值),**自帶非空 惟一屬性*s
  2. 約束字段爲自動增加,被約束的字段必須同時被key約束
  3. 若是事務rollback了這個auto_increment值就會浪費掉,從而形成間隙
  4. AUTO_INCREMENT數據列序號的最大值受該列的數據類型約束,一旦達到上限,AUTO_INCREMENT就會失效
create table t5(id int unique auto_increment,
               username char(10),
               pwd char(18));

insert into t5(username, pwd) values('henry', '123');
# 自增大小隻增不減
# 對於自增的字段,在用delete刪除後,再插入值,該字段仍按照刪除前的位置繼續增加
  • 應該用truncate清空表,比起delete一條一條地刪除記錄,truncate是直接清空表,在刪除大表時用它 mysql> truncate student;
# 也能夠建立表時指定auto_increment的初始值,注意初始值的設置爲表選項,應該放到括號外
create table student(id int primary key auto_increment,
                     name varchar(20),
                     gender enum('male','female') default 'male'
                    )auto_increment=3;
  • mysql自增步長
#設置步長
# sqlserver:自增步長
# 基於表級別,指定步爲2,從0開始計數
create table t1(id int unique auto_increment, age int
    )engine=innodb,auto_increment=2 default charset=utf8;
# mysql自增的步長:
show session variables like 'auto_inc%'; 
# 基於會話級別
set session auto_increment_increment=2;# 修改會話級別的步長
# 基於全局級別的
set global auto_increment_increment=2; # 修改全局級別的步長(全部會話都生效)
# 查看設置,從新登錄5.7版本直接失效
show variables like 'auto_incre%';
  • If the value of auto_increment_offset(起始偏移量) is greater than that of auto_increment_increment(步長), the value of auto_increment_offset is ignored.
  • 好比:設置auto_increment_offset=3,auto_increment_increment=2

1.5 primary key

  1. 一張表只能設置一個主鍵,innodb表中最好設置一個主鍵
  2. 主鍵約束這個字段,非空且惟一即:not null unique
create table t6(id int not null unique,
               name char(10) not null unique);
# 第一個指定爲not null nuique 字段被定義爲主鍵
create table t7(id int primary key,
               name char(10) not null unique);
  • 聯合主鍵
create table t8(id int,
               ip char(15),
               server char(10),
               port int,
               primary(ip, port))  # 聯合主鍵

Note(4)

  1. 主鍵爲了保證表中的每一條數據的該字段都是表格中的惟一值。換言之,它是用來獨一無二地確認一個表格中的每一行數據。
  2. 主鍵能夠包含一個字段或多個字段。當主鍵包含多個欄位時,稱爲組合鍵 (Composite Key),也能夠叫聯合主鍵
  3. 主鍵能夠在建新表格時設定 (運用 CREATE TABLE 語句),或是以改變現有的表格架構方式設定 (運用 ALTER TABLE)。
  4. 主鍵必須惟一,主鍵值非空;能夠是單一字段,也能夠是多字段組合。

1.6 foreign key

  1. 外鍵,涉及到兩張表
  2. 關聯的數據類型必須一致
  3. 被關聯的表必須惟一,mysql最好關聯主鍵
  4. 先建立外表,再建立關聯表
create table staff(id int primary key auto_increment,
                   age int,
                   gender enum('male', 'female'),
                   salary float(10,2),
                   hire_date date,
                   post_id int,
                   foreign key(post_id) references dept(pid);
                   
create table dept(pid int primary key, name char(10) not null nuique);
  • 級聯刪除和更新
  • foreign key(post_id) references dept(pid) on update cascade on delete cascade
create table staff(id int primary key auto_increment,
                   age int,
                   gender enum('male', 'female'),
                   salary float(10,2),
                   hire_date date,
                   post_id int,
                   foreign key(post_id) references dept(pid) 
                   on update cascade 
                   on delete set null);
                   
create table dept(pid int primary key, name char(10) not null nuique);

2. 修改表結構

  • 建立項目以前
  • 項目開發、運行過程當中

2.1 修改表名

# 修改表名
alter table 表名 rename 新表名;

2.2 增長/刪除字段

# 添加字段
alter table 表名 add 添加字段名 數據類型(寬度)  約束
# 刪除字段
alter table 表名 drop 刪除字段名;

2.3 修改字段

# 修改已經存在字段的類型、寬度 約束,不能修改字段名字
alter table 表名 modify 字段名 類型() 約束
# 修改已經存在字段的類型、寬度 約束、字段名字
alter table 表名 change 字段名 新字段名 類型() 約束

2.4 修改字段順序

# 把字段放在第一列
alter table 表名 modify age 類型+約束 first;
# 把字段放在id以後
alter table 表名 modify age int not null after id;
# 也能夠與 add、change 連用

2.5 修改字段約束

#去掉null約束
alter table t modify name char(10) null;
# 添加null約束
alter table t modify name char(10) not null;
# 去掉unique約束,特殊
alter table 表名 drop index 字段名;
# 添加unique約束
alter table 表名 modify 字段名 int unique;

2.6 修改庫的默認編碼

alter database 庫名 CHARACTER SET utf8;

2.7 操做主鍵add/drop

# 先刪除主鍵,刪除一個自增主鍵會報錯
# 須要先去掉主鍵的自增約束,而後再刪除主鍵約束
alter table 表名 drop primary key;
# 增長主鍵
alter table 表名 add primary key(id);

2.8 操做外鍵add/drop

# 添加外鍵
alter table 表名 add constraint 外鍵名 foreign key(字段) references press(字段);
# 刪除外鍵
alter table 表名 drop foreign key 外鍵名;

2.9 刪除表

drop table 表名;

3. 操做數據

兩張表的數據關係:多對一一對一多對多(書、做者)

3.1 多對一

  • 永遠在多的表中設置外鍵
  • 例如:一對多(或多對一):一個出版社能夠出版多本書
create table press(id int primary key auto_increment,
                   name varchar(20));

create table book(id int primary key auto_increment,
                  name varchar(20),
                  press_id int not null,
                  foreign key(press_id) references press(id)
                  on delete cascade
                  on update cascade);

insert into press(name) values('henry publisher'),
('echo publisher'),('dean publisher');

insert into book(name,press_id) values('henry',1),('echo',2),
('dean',2),('brad',3),('dianel',2),('oleg',3);

3.2 一對一

  • 外鍵+unique
  • 後出現的表中字段做爲外鍵
# 兩張表:學生表和客戶表
create table customer(id int primary key auto_increment,
                      name varchar(20) not null,
                      qq varchar(10) not null,
                      phone char(16) not null);

create table student(id int primary key auto_increment,
                     class_name varchar(20) not null,
                     customer_id int unique, #該字段必定要是惟一的
                     foreign key(customer_id) references customer(id) 
                     on delete cascade
                     on update cascade);
# 增長客戶
insert into customer(name,qq,phone) values('henry', '12345', 12312312311), ('echo','123123123',12312312311),('dean', '283818181', 12312312311), ('brad','283818181',12312312311), ('oleg', '888818181', 12312312311), ('dianel','112312312',12312312311);
# 增長學生
insert into student(class_name,customer_id) values('1班',3),('2班',4),('3班',5);

3.3 多對多

  • 利用第三張表,把兩個關聯關係的字段做爲第三張表的外鍵
create table author(id int primary key auto_increment,
                    name varchar(20));
create table book(id int primary key auto_increment,
                    name varchar(20));
# 這張表就存放做者表與書表的關係,即查詢兩者的關係查這表就能夠了
create table author_book(id int not null unique auto_increment,
                         author_id int not null,
                         book_id int not null,
                         constraint fk_author foreign key(author_id) references author(id)
                         on delete cascade
                         on update cascade,
                         constraint fk_book foreign key(book_id) references book(id)
                         on delete cascade
                         on update cascade,
                         primary key(author_id,book_id));

# 插入做者和書籍信息
insert into author(name) values('henry'),('echo'),('dean'),('diane');
insert into book(name) values('1'),('2'),('3'),('4'),('5'),('6')
insert into author_book(author_id,book_id) values(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(2,1),(2,6),(3,4),(3,5),(3,6),(4,1);

3.4 on delete/update

# 在父表上update/delete記錄時,同步update/delete掉子表的匹配記錄
cascade方式   

# 在父表上update/delete記錄時,將子表上匹配記錄的列設爲null要注意子表的外鍵列不能爲not null  
set null方式 

# 若是子表中有匹配的記錄,則不容許對父表對應候選鍵進行update/delete操做
No action方式

# 同no action, 都是當即檢查外鍵約束
Restrict方式

# 父表有變動時,子表將外鍵列設置成一個默認的值 但Innodb不能識別
Set default方式

4. 記錄操做

4.1 數據增長

  1. insert into 表名 values(值…):一次性能夠寫入多行數據
  2. insert into 表名(字段名) values(值...)
  3. insert into 表名 value(值…):一次性只能夠寫入行數據
# 寫入一行數據
insert into t1 values(1, 'henry', 19);
insert into t1 value(1, 'henry', 19);
# 寫入多行數據
insert into t1 values(1, 'henry', 19), (2, 'echo', 18);
# 指定字段寫入
insert into t1(name, age) value('henry', 19);

4.2 刪除

# 刪除條件匹配到的數據
delete form 表 where 條件;

4.3 修改

# 修改表中數據, set 後的字段能夠爲一個或多個
update 表 set 字段=值 where 條件;
# 注意null只能使用 is 匹配
where name is null;

1.4 查詢

  • select 語法
SELECT DISTINCT 字段1,字段2... FROM 表名
                              WHERE 條件
                              GROUP BY field
                              HAVING 篩選
                              ORDER BY field
                              LIMIT 限制條數

1. 基本查詢

# 查看錶中全部數據
select * from 表
# 查看指定字段
select 字段1,字段2... from 表
# 查看指定字段,自動去重
select distinct 字段1,字段2... from 表
# 數值型四則運算,併名別名顯示
select name,salary*12 (as) annual_salary form 表
# 數值型四則運算,併名別名, 拼接顯示
select concat ('姓名:',name,'薪資:',salary*12) (as) annual_salary form 表
# 使用':'進行拼接
select concat_ws (':', name,salary*12 (as) annual_salary) form 表
# 結合CASE語句:
SELECT(CASE
       WHEN emp_name = 'henry' THEN
           emp_name
       WHEN emp_name = 'echo' THEN
           CONCAT(emp_name,'_prefect')
       ELSE
           concat(emp_name, '_nice')
       END
       ) as new_name FROM employee;

2 . where

  • 逐行過濾
  1. 比較運算:<>/!= 不等於,> ,< ,>=,<=
  2. 範圍篩選
    • 多選一個
    • 在一個模糊的範圍裏
      • 在一個數值區間
      • 字符串模糊查詢
      • 正則匹配
  3. 邏輯運算—條件拼接
    • 與、或、非

2.1 比較/邏輯/身份運算

  • in / not in / is / is not
select * from t1 where salary>1000;
# 和數值類型無關
select * from t1 where salary=20000 or slary=30000;
# 邏輯運算
select * from t1 where gender='male' and age=18;
# 多選一,可使用 in
select 字段名,... from t1 where salary in (20000, 30000, 19000);
# not in 
select 字段名,... from t1 where salary not in (20000, 30000, 19000);
# is /is not 
select 字段名 from t1 where 字段 is null;

2.2 模糊查找(3)

  1. between…and...
# between ... and ...
select  name,salary from t1 where salary between 10000 and 20000
  1. 字符串模糊匹配,like
# like , % 通配符,匹配任意長度,任意內容
select * from t1 where name like '程%';
# like , _ 通配符,匹配一個任意字符
select * from t1 where name like '程_';
# like , 以 n 結尾
select * from t1 where name like '%n';
  1. 正則匹配,regexp
select * from t1 where name regexp 正則表達式;
SELECT * FROM employee WHERE emp_name REGEXP 'on$';

3. 分組聚合

3.1 group by

  • group by 後的這個字段,也就是post字段中的每個不一樣的項目保留下來
  • 而且把值是這一項的全部行歸爲一組,並只顯示組中第一個
# 顯示一個組的第一個,必須有group的字段
select post from employee group by post;
# distinct 基於group by完成

3.2 聚合函數(5)

  • 把多行的同一字段進行一些統計,最終獲得一個結果
  1. count(字段):統計這個字段有多少項
  2. sum(字段):統計這個字段對應的數值和,數值類型
  3. avg(字段):平均值
  4. min、max
    • 只能取到最小、最大值,但不能取到對應的其餘項(名字),顯示組中第一項
    • 使用多表查詢
  • count
select count(*/ 主鍵) from employee;
# 只算id不爲空的字段個數
select count(id) from employee;
  • avg/sum
select avg(salary) from employee;
select sum(salary) from employee;

3.3 分組聚合

  • group by
# 分別對各個組,統計人數
select post,count(*) from employee group by post;
# 對某一組進行統計人數
select post,count(*) from employee where post='teacher';
# 各部門的平均薪資
select post,avg(salary) from employee group by post;
# 最晚入職
select max(hire_date) from employee group by post;
# 最先入職
select min(hire_date) from employee group by post;
  • 查詢分組內全部成員名
    • group_concat()
# 查詢崗位名以及崗位包含的全部員工名字
select post, group_concat(emp_name) from employee group by post;
# 查詢崗位名以及各崗位內包含的員工個數
select post, count(id) from employee group by post;
# 查詢公司內男員工和女員工的個數
select gender, count(id) from employee group by gender;

Note3(2)

  1. 老是根據會重複的項進行分組
  2. 分組老是和聚合函數一塊兒使用

3.4 having

  • having 條件,組過濾, 通常與group一塊兒使用
  • Where 發生在分組group by以前,於是Where中能夠有任意字段,可是絕對不能使用聚合函數。
  • Having發生在分組group by以後,於是Having中可使用分組的字段,沒法直接取到其餘字段,可使用聚合函數
# 部門人數大於3
select post from employee group by post having count(*) > 3;
# 平均薪資大於10000
select post from employee group by post having avg(salary) > 10000;
# 過濾整張表,必須有 age 字段,不然報錯
select emp_name, age from employee having avg(age)>18;
  • having 過濾示例
# 查詢各崗位內包含的員工個數小於2的崗位名、崗位內包含員工名字、個數
select post, group_concat(emp_name), count(*) from employee group by post having count(id) < 2;
# 查詢各崗位平均薪資大於10000的崗位名、平均工資
select post,avg(salary) from employee group by post having avg(salary) > 10000;
# 查詢各崗位平均薪資大於10000且小於20000的崗位名、平均工資
select post,avg(salary) from employee group by post having avg(salary) > 10000 and avg(salary) < 20000;
# 使用 between ... and...
select post,avg(salary) from employee group by post having avg(salary) between 10000 and 20000;

3.5 order by

# desc 表示降序排
# asc 表示生序排列,默認值
select * from employee order by salary desc;
# 多個個字段排序,先根據第一個字段排列後,再根據第二個字段排列
select * from employee order by age asc, salary desc;
  • having 和 order by綜合使用示例
# 查詢各崗位平均薪資大於10000的崗位名、平均工資,結果按平均薪資升序排列
select post, avg(salary) from employee group by post having avg(salary) > 10000 order by avg(salary) asc;
# 查詢各崗位平均薪資大於10000的崗位名、平均工資,結果按平均薪資降序排列
select post, avg(salary) from employee group by post having avg(salary) > 10000 order by avg(salary) desc;

3.6 limit

# 分頁顯示
# 默認從0開始,顯示前5個
select * from employee limit 5;
# 顯示下5個, 5+1 位置開始取
# limit m,n 表示從m+1開始取到5個
limit n offset m等價於limit m,n

select * from employee limit 5,5;
# 顯示下5個
select * from employee limit 10,5;

Note3(3)

  1. 關鍵字執行的優先級(8)
    • join優先級要高於from
    • from—> where —> group by —> select —> distinct —> having —> order by —>limit
  2. 用戶認證—>解析、優化、執行sql、找到存儲引擎
  3. select以前把行數限制在小的範圍

sql語句執行順序

4. 多表查詢

  • 數據準備
#建表
create table department(id int,
                        name varchar(20) );

create table staff(id int primary key auto_increment,
                   name varchar(20),
                   gender enum('male','female') not null default 'male',
                   age int,
                   dep_id int);
#插入數據
insert into department values(200,'技術'),(201,'人力資源'),(202,'銷售'),(203,'運營');
insert into staff(name,gender,age,dep_id) values
('henry','male',18,200), 
('echo','female',48,201),
('dean','male',38,201),
('diane','female',28,202),
('oleg','male',18,200),
('iris','female',18,204);

#查看錶結構和數據
mysql> desc department;
mysql> desc employee;

mysql> select * from department;
mysql> select * from employee;

4.1 連表查詢

  • 一般使用內鏈接和左外鏈接
select 字段列表
    FROM 表1 INNER|LEFT|RIGHT JOIN 表2
    ON 表1.字段 = 表2.字段;
  1. 交叉鏈接:不適用任何匹配條件。生成笛卡爾積
# 笛卡爾積
select 字段 from t1,t2 where 字段1=字段2;
# 連表查詢,staff,department 兩個表,和 inner join 效果一致
select * from staff, department as dept where dep_id=dept.id;
  1. 內鏈接(inner join)
    • 兩張表條件不匹配的項不出現結果中
select 字段 from t1 inner join t2 on t1(字段1) = t2(字段2);
  1. 外鏈接
    1. 左外鏈接(left join):全量顯示左邊的表中數據
      • 本質就是:在內鏈接的基礎上增長左邊有右邊沒有的結果
    2. 右外鏈接(right join):全量顯示右邊的表中數據
      • 本質就是:在內鏈接的基礎上增長右邊有左邊沒有的結果
    3. 全外鏈接(左外鏈接 union 右外鏈接):mysql沒有全外鏈接
      • 在內鏈接的基礎上增長左邊有右邊沒有的和右邊有左邊沒有的結果
    4. sqlserver中有全外鏈接(full join),沒有右外鏈接
# t1鏈接t2,顯示全量的左表,只顯示匹配到的t2
select 字段 from t1 left join t2 on t1(字段1) = t2(字段2);
select 字段 from t1 right join t2 on t1(字段1) = t2(字段2);
# 全鏈接
select 字段 from t1 left join t2 on t1(字段1) = t2(字段2) union
select 字段 from t1 right join t2 on t1(字段1) = t2(字段2);
# 經過左外、和右外鏈接實現全外鏈接示例
select * from staff left join department as dept on dep_id = dept.id union select * from staff right join department as dept on dep_id = dept.id;
  • 注意 union與union all的區別:union會去掉相同的紀錄
  1. 連表查詢示例
    • 連表查詢效率更高
# 之內鏈接的方式查詢staff和department表,而且staff表中的age字段值必須大於25,即找出年齡大於25歲的員工以及員工所在的部門
# 此時括號能夠省略
select staff.name, dept.name from staff left join department as dept on dep_id = dept.id where age > 25;
# 之內鏈接的方式查詢staff和department表,而且以age字段的升序方式顯示
select * from staff inner join department as dept on dep_id = dept.id order by age;

4.2 子查詢

  1. 基本語法
1:子查詢是將一個查詢語句嵌套在另外一個查詢語句中。
2:內層查詢語句的查詢結果,能夠爲外層查詢語句提供查詢條件。
3:子查詢中能夠包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等關鍵字
4:還能夠包含比較運算符:= 、 !=、> 、<等
# 子表中匹配到惟一值
select name from emp where dep_id = (select id from department where name='技術');
# 子表中匹配到多個值
select name from emp where dep_id in (select id from department where name in ('技術', '銷售'));
  1. 帶in關鍵字的查詢
  • 使用in時,後面的表中字段只能有一個字段
# 查詢平均年齡在25歲以上的部門名
select name from department where id in (select dep_id from staff group by dep_id having avg(age) > 25);
# 查看技術部員工姓名
select name from staff where dep_id in (select id from department where name = '技術' )
# 查看不足1人的部門名(子查詢獲得的是有人的部門id)
select name from department where id not in (select dep_id from staff group by dep_id);
  1. 帶比較運算符
# 查詢大於全部人平均年齡的員工名、年齡
select name, age from staff where age > (select avg(age) from staff);
# 查詢大於部門內平均年齡的員工名、年齡
select name, age from staff t1 inner join (select dep_id, avg(age) avg_age from staff group by dep_id) t2 on t1.dep_id = t2.dep_id where t1.age > t2.avg_age;
  1. 帶EXISTS關鍵字的子查詢
  • EXISTS關字鍵字表示存在。在使用EXISTS關鍵字時,內層查詢語句不返回查詢的記錄。而是返回一個真假值
  • 當返回True時,外層查詢語句將進行查詢;當返回值爲False時,外層查詢語句不進行查詢
# exists後爲真
select * from staff where exists (select id from department where id=200);
# 輸出staff中全部數據
# exists後爲假
select * from staff where exists (select id from department where id=200);
# 輸出爲空
  1. 示例
    • 查詢每一個部門最新入職的那位員工
# 連表查詢
select t1.emp_name, t1.hire_date, t1.post from employee as t1 inner join (select depart_id, max(hire_date) as max_date from employee group by depart_id) as t2 on t1.depart_id = t2.depart_id where t1.hire_date = t2.max_date;
# 子查詢
select t3.emp_name,t3.post,t3.hire_date from employee as t3 where id in (select (select id from employee as t2 where t2.depart_id=t1.depart_id order by hire_date desc limit 1) from employee as t1 group by depart_id);

1.5 mysql索引

1. 存儲過程

# 1.準備表
create table s_test(id int,
                name varchar(20),
                gender char(6),
                email varchar(50));
# 2.建立存儲過程,實現批量插入記錄
delimiter $$ #聲明存儲過程的結束符號爲$$
create procedure auto_insert()
BEGIN
    declare i int default 1;
    while(i<3000000)do
        insert into s_test values(i,'henry','male',concat('henry',i,'@qq.com'));
        set i=i+1;
    end while;
END$$ #$$結束
delimiter ; #從新聲明分號爲結束符號
# 3.查看存儲過程
show create procedure auto_insert\G 
# 4.調用存儲過程
call auto_insert();
# 在寫入的時候不更新索引表,只針對myisam生效
ALTER TABLE table_name DELAY_KEY_WRITE= 1;

2. 初識索引

  • 索引是應用程序設計和開發的一個重要方面。若索引太多,應用程序的性能可能會受到影響。而索引太少,對查詢性能又會產生影響,要找到一個平衡點,這對應用程序的性能相當重要。
  • 場景:某臺MySQL服務器iostat顯示磁盤使用率一直處於100%,通過分析後發現是因爲開發人員添加了太多的索引,在刪除一些沒必要要的索引以後,磁盤使用率立刻降低爲20%。可見索引的添加也是很是有技術含量的。

2.1 概念

  • 索引在MySQL中也叫是一種「鍵」,是存儲引擎用於快速找到記錄的一種數據結構
  • 創建起的一個在存儲表階段的一個存儲結構可以在查詢的時候加速
  • 出於效率方面的考慮,InnoDB數據表的數據行級鎖定實際發生在它們的索引上,而不是數據表自身上。顯然,數據行級鎖定機制只有在有關的數據表有一個合適的索引可供鎖定的時候才能發揮效力

2.2 索引的重要性

  1. 讀寫比例:10:1,讀的速度是數據庫的關鍵
    • 讀取硬盤的io操做時間要遠遠長於cpu執行指令的時間
    • 儘可能減小io次數纔是關鍵
    • 索引對性能的影響隨着數據量的增長愈發重要
    • 訪問磁盤的成本大概是訪問內存的十萬倍左右
  2. 磁盤IO與預讀性原理,一次讀取一個block
    • 訪問磁盤,那麼這裏先簡單介紹一下磁盤IO和預讀,磁盤讀取數據靠的是機械運動,每次讀取數據花費的時間能夠分爲尋道時間旋轉延遲傳輸時間三個部分,尋道時間指的是磁臂移動到指定磁道所須要的時間,主流磁盤通常在5ms如下;旋轉延遲就是咱們常常據說的磁盤轉速,
    • 一臺500 -MIPS(Million Instructions Per Second)的機器每秒能夠執行5億條指令。
    • 考慮到磁盤IO是很是高昂的操做,計算機操做系統作了一些優化,當一次IO時,不光把當前磁盤地址的數據,並且把相鄰的數據也都讀取到內存緩衝區內,由於局部預讀性原理告訴咱們,當計算機訪問一個地址的數據的時候,與其相鄰的數據也會很快被訪問到。每一次IO讀取的數據咱們稱之爲一頁(page)。具體一頁有多大數據跟操做系統有關,通常爲4k或8k,也就是咱們讀取一頁內的數據時候,實際上才發生了一次IO,這個理論對於索引的數據結構設計很是有幫助。
    • 4096bytes, 4k(linux)
    • oracle會一次讀取2個block塊
    • mysql會一次讀取4個block塊

2.3 索引原理

  • 本質都是:經過不斷地縮小想要獲取數據的範圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是說,有了這種索引機制,咱們能夠老是用同一種查找方式來鎖定數據。
  • 索引會加速搜索的速度,但寫的速度很慢。每次寫入數據時都必須整理樹形結構。

2.4 數據庫存儲方式

  1. 平衡樹 balance tree b樹

    1. 寫入數據:速度較慢,須要整理數據

    2. b樹在範圍查詢b樹不佔優點(root、leaf、branch)演變成雙向鏈式結構

    3. 在b樹基礎上的改良:b+樹(innodb 默認結構)(2

      • 目的:每次查找數據時把磁盤IO次數控制在一個很小的數量級,最好是常數數量級。
      1. 分支節點和根節點不在存儲實際數據
        • 讓分支和根節點能存儲更多的索引信息
      2. 在葉子節點之間加入雙向的鏈式結構方便在查詢中的範圍條件
    4. 索引字段要儘可能的小:經過上面的分析,咱們知道IO次數取決於b+數的高度h,假設當前數據表的數據爲N,每一個磁盤塊的數據項的數量是m,則有h=㏒(m+1)N,當數據量N必定的狀況下,m越大,h越小;而m = 磁盤塊的大小 / 數據項的大小,磁盤塊的大小也就是一個數據頁的大小,是固定的,若是數據項佔的空間越小,數據項的數量越多,樹的高度越低。這就是爲何每一個數據項,即索引字段要儘可能的小,好比int佔4字節,要比bigint8字節少一半。這也是爲何b+樹要求把真實的數據放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的數據項會大幅度降低,致使樹增高。當數據項等於1時將會退化成線性表。

    • B-Tree中一次檢索最多須要h-1次I/O(根節點常駐內存),漸進複雜度爲O(h) = O(logdN) 。通常實際應用中,出度d是很是大的數字,一般超過100,所以h很是小(一般不超過3)。(h表示樹的高度 & 出度d表示的是樹的度,即樹中各個節點的度的最大值)
    1. 索引的最左匹配特性:當b+樹的數據項是複合的數據結構,好比(name,age,sex)的時候,b+樹是按照從左到右的順序來創建搜索樹的,好比當(張三,20,F)這樣的數據來檢索的時候,b+樹會優先比較name來肯定下一步的所搜方向,若是name相同再依次比較age和sex,最後獲得檢索的數據;但當(20,F)這樣的沒有name的數據來的時候,b+樹就不知道下一步該查哪一個節點,由於創建搜索樹的時候name就是第一個比較因子,必需要先根據name來搜索才能知道下一步去哪裏查詢。好比當(張三,F)這樣的數據來檢索時,b+樹能夠用name來指定搜索方向,但下一個字段age的缺失,因此只能把名字等於張三的數據都找到,而後再匹配性別是F的數據了, 這個是很是重要的性質,即索引的最左匹配特性
  2. 樹的高度會影響索引的效率

    • 對哪一列建立索引,選擇儘可能短的列作索引
    • 區分度高的列建索引,重複率超過10%就不適合建立索引
    • 儘可能選擇區分度高的列做爲索引,區分度的公式是count(distinct 字段)/count(*),表示字段不重複的比例。
  3. 索引特色(2)

    • 加速讀取,但犧牲了寫的速度
    • 每一個節點存儲數據的地址
  4. mysql中全部的b+樹索引的高度都基本上控制在3

    • io操做的次數很是穩定(3)
    • 有利於經過範圍查詢
    • 在數據庫中,B+樹的高度通常都在2~4層,這也就是說查找某一個鍵值的行記錄時最多隻須要2到4次IO,這倒不錯。由於當前通常的機械硬盤每秒至少能夠作100次IO,2~4次的IO意味着查詢時間只須要0.02~0.04秒。

2.4 彙集索引和輔助索引

  1. 數據庫中的B+樹索引能夠分爲彙集索引(clustered index)和輔助索引(secondary index)

  2. 彙集索引:數據直接存儲在樹結構的葉子節點

    • 如用戶須要查找一張表,查詢最後的10位用戶信息,因爲B+樹索引是雙向鏈表,因此用戶能夠快速找到最後一個數據頁,並取出10條記錄
    # InnoDB存儲引擎表是索引組織表,即表中數據按照主鍵順序存放。
    1. 而彙集索引(clustered index)就是按照每張表的主鍵構造一棵B+樹,同時葉子結點存放的即爲整張表的行記錄數據,也將彙集索引的葉子結點稱爲數據頁。
    2. 彙集索引的這個特性決定了索引組織表中數據也是索引的一部分。同B+樹數據結構同樣,每一個數據頁都經過一個雙向鏈表來進行連接。
    # 若是未定義主鍵,MySQL取第一個惟一索引(unique)並且只含非空列(NOT NULL)做爲主鍵,InnoDB使用它做爲聚簇索引。  
    1. 若是沒有這樣的列,InnoDB就本身產生一個這樣的ID值,它有六個字節,並且是隱藏的,使其做爲彙集索引。
    # 因爲實際的數據頁只能按照一棵B+樹進行排序,所以每張表只能擁有一個彙集索引。
    1. 在多數狀況下,查詢優化器傾向於採用彙集索引。由於彙集索引可以在B+樹索引的葉子節點上直接找到數據。
    2. 此外因爲定義了數據的邏輯順序,彙集索引可以特別快地訪問針對範圍值得查詢。
    • 能夠經過添加主鍵的方式完成索引的創建
    alter table t1 add primary key(id);
    alter table t1 modify id not null unique;
    • 彙集索引的好處之一:它對主鍵的排序查找和範圍查找速度很是快,葉子節點的數據就是用戶所要查詢的數據。
    • 彙集索引的好處之二:範圍查詢(range query),即若是要查找主鍵某一範圍內的數據,經過葉子節點的上層中間節點就能夠獲得頁的範圍,以後直接讀取數據頁便可。
  3. 輔助索引:數據不直接存儲在樹中

    • 須要回表
    • 表中除了彙集索引外其餘索引都是輔助索引(Secondary Index,也稱爲非彙集索引),與彙集索引的區別是:輔助索引的葉子節點不包含行記錄的所有數據。葉子節點除了包含鍵值之外,每一個葉子節點中的索引行中還包含一個書籤(bookmark)。該書籤用來告訴InnoDB存儲引擎去哪裏能夠找到與索引相對應的行數據。

    innodb輔助索引

    • 輔助索引的存在並不影響數據在彙集索引中的組織,所以每張表上能夠有多個輔助索引,但只能有一個彙集索引。當經過輔助索引來尋找數據時,InnoDB存儲引擎會遍歷輔助索引並經過葉子級別的指針得到索引的主鍵,而後再經過主鍵索引來找到一個完整的行記錄。
  4. 彙集和輔助索引對比

    1. 彙集索引與輔助索引相同的是:無論是彙集索引仍是輔助索引,其內部都是B+樹的形式,即高度是平衡的,葉子結點存放着全部的數據。彙集索引與輔助索引不一樣的是:葉子結點存放的是不是一整行的信息
    2. 彙集索引
      • 紀錄的索引順序與順序相同,所以更適合between and和order by操做
      • 葉子結點直接對應數據從中間級的索引頁的索引行直接對應數據頁
      • 每張表只能建立一個彙集索引
    3. 非彙集索引
      • 索引順序和物理順序無關
      • 葉子結點不直接指向數據頁
      • 每張表能夠有多個非彙集索引,須要更多磁盤和內容
      • 多個索引會影響insert和update的速度
  5. innodb中彙集索引和輔助索引並存(都是b+樹)

    • 數據和索引存在一塊兒
    • 除了主鍵以外全部的索引都是輔助索引
  6. myisam中只有輔助索引

    • 葉子節點存儲數據的主鍵的值
    • 經過主鍵再查找數據
  7. 須要注意的是innodb表的索引會存放於s1.ibd文件中,而myisam表的索引則會有單獨的索引文件table1.MYI

  8. MySAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在innodb中,表數據文件自己就是按照B+Tree(BTree即Balance Tree)組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以innodb表數據文件自己就是主索引。由於inndob的數據文件要按照主鍵彙集,因此innodb要求表必需要有主鍵(Myisam能夠沒有),若是沒有顯式定義,則mysql系統會自動選擇一個能夠惟一標識數據記錄的列做爲主鍵,若是不存在這種列,則mysql會自動爲innodb表生成一個隱含字段做爲主鍵,這字段的長度爲6個字節,類型爲長整型.

3. 使用索引

3.1 索引兩大類型

  1. 咱們能夠在建立上述索引的時候,爲其指定索引類型,分兩類
    • hash類型的索引:查詢單條快,範圍查詢慢
      • 只有memory(內存)存儲引擎支持哈希索引,哈希索引用索引列的值計算該值的hashCode,而後在hashCode相應的位置存執該值所在行數據的物理位置,由於使用散列算法,所以訪問速度很是快,可是一個值只能對應一hashCode,並且是散列的分佈方式,所以哈希索引不支持範圍查找和排序的功能。
    • btree類型的索引:b+樹,層數越多,數據量指數級增加(咱們就用它,由於innodb默認支持它)
  2. 不一樣的存儲引擎支持的索引類型也不同
    • InnoDB 支持事務,支持行級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
    • MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
    • Memory 不支持事務,支持表級別鎖定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
    • NDB 支持事務,支持行級別鎖定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
    • Archive 不支持事務,支持表級別鎖定,不支持 B-tree、Hash、Full-text 等索引;
  3. 除此以外還有全文索引,即FULLTEXT用於搜索很長一篇文章的時候,效果最好。用在比較短的文本,若是就一兩行字的,普通的 INDEX 也能夠。但其實對於全文搜索,咱們並不會使用MySQL自帶的該索引,而是會選擇第三方軟件如Sphinx,專門來作全文搜索。
  4. 其餘的如空間索引SPATIAL,瞭解便可,幾乎不用。

3.2 索引的種類

  1. primary key 主鍵 自帶彙集索引 和約束:非空+惟一
    • 聯合主鍵
  2. unique 區分度最高 自帶輔助索引 和約束:惟一
    • 聯合惟一
  3. index 輔助索引 輔助索引 沒有約束
    • 聯合索引,根據兩個字段創建索引

3.3 使用索引

  • 添加主鍵會自動添加爲索引
  • 添加unique也會自動添加爲索引
# 方法一:建立表時
create table 表(字段...,
               index|unique|fulltext|spatial|key 
               索引名稱 on 表(字段1,字段2...));
# 方法二:CREATE在已存在的表上建立索引,經常使用方法
create index(索引類型,一般使用index) 索引名稱 on 表(字段1,字段2...);
# 方法三:ALTER TABLE在已存在的表上建立索引
alter table 表名 add index 索引名稱 on 表(字段1,字段2...);
# 刪除索引
drop index 索引名 on 表名字;
# 查看錶s1的索引
show index from s1;
  • 不添加索引的時候確定慢
  • 查詢的字段不是索引字段也慢

3.4 索引不生效

  • 範圍、條件字段是否參與計算、列的區分度、列的長度、條件 and/or,聯合索引的前綴問題
  1. 要查詢的範圍越大,索引效果越不明顯,越費時
    • 和比較運算符有關的,大於、小於、不等於、between … and ...
    • like,結果範圍大,like abc%能夠生效%abc索引不生效
select * from 表 where id between 1000000 and 1000005;
# 使用like
select * from 表 where emial like '%abc';
  1. 一列的區分度不高
    • 即範圍過大
# 而對於區分度低的字段,沒法找到大小關係,由於值都是相等的,毫無疑問,還想要用b+樹存放這些等值的數據,只能增長樹的高度,字段的區分度越低,則樹的高度越高。
  1. 索引列不能參與計算,不能包含函數
select * from s1 where id*10 = 1000000;
  1. 對兩列內容進行條件查詢
    • and:優先選擇有索引且樹形結構更好的進行查找,快速縮小範圍
    • or:若是存在沒有索引項,索引效果不生效,只是根據條件從左到右依次篩選
      • 條件中帶有or的想要命中索引,這些條件中全部列都是索引列
  2. 最左前綴匹配原則,很是重要的原則,對於組合索引mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配(指的是範圍大了,有索引速度也慢),好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。
  3. 其餘狀況
    1. 索引字段使用函數
    2. 排序條件爲索引,則select字段必須也是索引字段,不然沒法命中
      • 若是對主鍵排序,則仍是速度很快:
    3. create index xxxx on tb(title(19)) # text類型,必須制定長度

小結:索引不生效狀況

  1. 在聯合索引中若是使用or條件索引不生效
  2. 條件必須含有建立索引的第一個字段(最左前綴原則)
    • id列能夠命中索引
  3. 整個條件中,一開始出現模糊匹配的那一刻,索引就失效

3.5 聯合索引

  • 查找老是兩個(多)個條件
  • 從本質上來講,聯合索引就是一棵B+樹,不一樣的是聯合索引的鍵值得數量不是1,而是>=2
  • 在第一個鍵相同的狀況下,已經對第二個鍵進行了排序處理
create index ind_mix on s1(id, email);
# 對於聯合索引(a,b),下述語句能夠直接使用該索引,無需二次排序
select ... from table where a=xxx order by b;
# 而後對於聯合索引(a,b,c)來首,下列語句一樣能夠直接經過索引獲得結果
select ... from table where a=xxx order by b;
select ... from table where a=xxx and b=xxx order by c;
# 可是對於聯合索引(a,b,c),下列語句不能經過索引直接獲得結果,還須要本身執行一次filesort操做,由於索引(a,c)並未排序
select ... from table where a=xxx order by c;
  1. 應用場景
    1. 只對a,b,c條件進行索引
    2. 對b,對c進行單列索引
  2. 單列索引
    1. 區分度高的列,創建索引,條件的範圍儘可能小
    2. 條件中的列不參與計算,使用and 做爲條件鏈接
    3. 使用or鏈接多個條件,在知足上述條件的基礎上,對or相關的全部列建立索引

3.6 覆蓋/合併索引

  1. InnoDB存儲引擎支持覆蓋索引(covering index,或稱索引覆蓋),即從輔助索引中就能夠獲得查詢記錄,而不須要查詢彙集索引中的記錄。
  2. 覆蓋索引的一個好處是:輔助索引不包含整行記錄的全部信息,故其大小要遠小於彙集索引,所以能夠減小大量的IO操做
  • 若是使用索引做爲條件查詢,查詢完畢以後,不須要回表查即覆蓋索引
  • 對兩個字段分別建立索引,因爲sql讓兩個索引同時生效,那麼這個時候這兩個索引就成爲了合併索引

3.7 執行計劃

# 執行計劃,並不會真正執行sql語句,給出一個執行計劃
explain select id from s1 where id = 1000000;
  • 執行計劃使用場景
    1. 測試sql語句是否能夠知足數據量多的狀況下的效率

  • 建表、使用sql須要注意
    • char代替varchar
    • 連表代替子查詢
    • 建立表的時候,固定長度的字段在前面

3.8 慢查詢優化流程

  1. 先運行看看是否真的很慢,注意設置SQL_NO_CACHE
  2. where條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的where都應用到表中返回的記錄數最小的表開始查起,單表每一個字段分別查詢,看哪一個字段的區分度最高
  3. explain查看執行計劃,是否與1預期一致(從鎖定記錄較少的表開始查詢)
  4. order by limit 形式的sql語句讓排序的表優先查
  5. 瞭解業務方使用場景
  6. 加索引時參照建索引的幾大原則
  7. 觀察結果,不符合預期繼續從0分析

4. 庫的備份與恢復

# 語法:
mysqldump -h服務器 -u用戶名 -p密碼 數據庫名 > 備份文件.sql
# 示例:
# 單庫備份
mysqldump -uroot -p123 庫名 > 備份文件名(路徑)
mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql
# 多庫備份,導入時不須要指定庫名,會覆蓋庫名相同的庫
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql
# 備份全部庫
mysqldump -uroot -p123 --all-databases > all.sql
# 方法一:不使用 --databases 參數
mysql -u用戶名 -p密碼  庫名 < 備份文件名 
# 方法二:
mysql> use db1;
# 關閉二進制日誌,只對當前session生效
mysql> SET SQL_LOG_BIN=0;  
mysql> source /root/db1.sql

1.6 pymysql模塊

1. 第三方模塊

mysql -uroot -p
mysql.exe              # mysql的一個客戶端
  • ip port 用戶名 密碼 使用的庫 鏈接mysqld的server端
import pymysql
con = pymysql.connect(host='127.0.0.1', user='root', password='123', database='test')
# 數據庫操做符,遊標,dict取值,默認元組
cur = con.cursor(pymysql.cursors.DictCursor)
# 操做
cur.execute('sql語句')
# 獲取返回值,cur相似操做文件的遊標指針
ret = cur.fetchone()/ fetchmany(n)/ fetchall()
con.commit()
con.close()
  • localhost:不過網卡,127.0.0.1過網卡

2. 事務和鎖

# 開啓事務
begin; 或者 start transction;
# 查詢id值,for update添加行鎖;
select * from emp where id = 1 for update;
# 完成更新
update emp set salary=10000 where id = 1;
# 提交事務
commit;

3. sql注入

-- 表示註釋掉以後的sql語句
select * from userinfo where name = 'alex' ;-- and password = '792164987034';
select * from userinfo where name = 219879 or 1=1 ;-- and password = 792164987034;
select * from userinfo where name = '219879' or 1=1 ;-- and password = '792164987034';
  1. 怎麼避免sql注入問題
sql = 'select * from 表'
# 參數爲可迭代對象,使用execut拼接
cur.execute(sql, (username, password))
cur.close()
con.close()
  1. 回滾操做
    • 修改表中數據必須使用commit() 方法
import pymysql
# 打開數據庫鏈接
db = pymysql.connect("localhost","testuser","test123","TESTDB" )
# 使用cursor()方法獲取操做遊標 
cursor = db.cursor()
# SQL 插入語句
sql = """INSERT INTO EMPLOYEE(FIRST_NAME,
         LAST_NAME, AGE, SEX, INCOME)
         VALUES ('Mac', 'Mohan', 20, 'M', 2000)"""
try:
   cursor.execute(sql) # 執行sql語句
   db.commit()         # 提交到數據庫執行
except:
   db.rollback()       # 若是發生錯誤則回滾
# 關閉數據庫鏈接
db.close()
  1. 查詢操做
    • Python查詢Mysql使用 fetchone() 方法獲取單條數據, 使用fetchall() 方法獲取多條數據。
    • fetchone(): 該方法獲取下一個查詢結果集。結果集是一個對象
    • fetchall(): 接收所有的返回結果
    • rowcount: 這是一個只讀屬性,並返回執行execute()方法後影響的行數。
import pymysql
# 打開數據庫鏈接
db = pymysql.connect("localhost", "root", "root", "day40")
# 使用cursor()方法獲取操做遊標
cur = db.cursor()
# SQL 查詢語句
sql = "SELECT * FROM employee \
       WHERE salary > %s" % (1000)
try:
    ret = cur.execute(sql)           # 執行SQL語句
    print(ret)                       # ret爲數據行數
    results = cur.fetchall()         # 獲取全部記錄列表
    for row in results:
        id = row[0]
        name = row[1]
        gender = row[2]
        age = row[3]
        hire_date = row[4]
        print("id=%s,name=%s,gender=%s,age=%s,hire_date=%s"%(id, name, gender, age, hire_date))
except:
    print("Error: unable to fetch data")
# 關閉數據庫鏈接
db.close()

1.7 數據庫優化

  • sql優化:索引、盡力那個把條件範圍都寫在where裏,儘可能用連表查
  • 如何建立表:把固定長度的字段放在前面、分庫分表
  • innodb中的外鍵是特有的
相關文章
相關標籤/搜索