Python學習-基礎篇9 mysql相關

 

mysql一:初始數據庫html

一 數據庫管理軟件的由來

基於咱們以前所學,數據要想永久保存,都是保存於文件中,毫無疑問,一個文件僅僅只能存在於某一臺機器上。python

若是咱們暫且忽略直接基於文件來存取數據的效率問題,而且假設程序全部的組件都運行在一臺機器上,那麼用文件存取數據,並無問題。mysql

很不幸,這些假設都是你本身意淫出來的,上述假設存在如下幾個問題。。。。。。linux

一、程序全部的組件就不可能運行在一臺機器上ios

#由於這臺機器一旦掛掉則意味着整個軟件的崩潰,而且程序的執行效率依賴於承載它的硬件,而一臺機器機器的性能總歸是有限的,受限於目前的硬件水平,就一臺機器的性能垂直進行擴展是有極限的。

#因而咱們只能經過水平擴展來加強咱們系統的總體性能,這就須要咱們將程序的各個組件分佈於多臺機器去執行。

二、數據安全問題程序員

#根據1的描述,咱們將程序的各個組件分佈到各臺機器,但需知各組件仍然是一個總體,言外之意,全部組件的數據仍是要共享的。但每臺機器上的組件都只能操做本機的文件,這就致使了數據必然不一致。

#因而咱們想到了將數據與應用程序分離:把文件存放於一臺機器,而後將多臺機器經過網絡去訪問這臺機器上的文件(用socket實現),即共享這臺機器上的文件,共享則意味着競爭,會發生數據不安全,須要加鎖處理。。。。

三、併發 redis

根據2的描述,咱們必須寫一個socket服務端來管理這臺機器(數據庫服務器)上的文件,而後寫一個socket客戶端,完成以下功能:算法

#1.遠程鏈接(支持併發)
#2.打開文件
#3.讀寫(加鎖)
#4.關閉文件

總結:sql

#咱們在編寫任何程序以前,都須要事先寫好基於網絡操做一臺主機上文件的程序(socket服務端與客戶端程序),因而有人將此類程序寫成一個專門的處理軟件,這就是mysql等數據庫管理軟件的由來,但mysql解決的不只僅是數據共享的問題,還有查詢效率,安全性等一系列問題,總之,把程序員從數據管理中解脫出來,專一於本身的程序邏輯的編寫。

二 數據庫概述 

1 什麼是數據(Data) mongodb

描述事物的符號記錄稱爲數據,描述事物的符號既能夠是數字,也能夠是文字、圖片,圖像、聲音、語言等,數據由多種表現形式,它們均可以通過數字化後存入計算機

在計算機中描述一個事物,就須要抽取這一事物的典型特徵,組成一條記錄,就至關於文件裏的一行內容,如:

1 egon,male,18,1999,山東,計算機系,2017,oldboy

單純的一條記錄並無任何意義,若是咱們按逗號做爲分隔,依次定義各個字段的意思,至關於定義表的標題

1 name,sex,age,birth,born_addr,major,entrance_time,school #字段
2 egon,male,18,1999,山東,計算機系,2017,oldboy #記錄

這樣咱們就能夠了解egon,性別爲男,年齡18歲,出生於1999年,出生地爲山東,2017年考入老男孩計算機系

2 什麼是數據庫(DataBase,簡稱DB)

數據庫即存放數據的倉庫,只不過這個倉庫是在計算機存儲設備上,並且數據是按必定的格式存放的

過去人們將數據存放在文件櫃裏,如今數據量龐大,已經再也不適用

數據庫是長期存放在計算機內、有組織、可共享的數據便可。

數據庫中的數據按必定的數據模型組織、描述和儲存,具備較小的冗餘度、較高的數據獨立性和易擴展性,並可爲各類 用戶共享

3 什麼是數據庫管理系統(DataBase Management System 簡稱DBMS)

在瞭解了Data與DB的概念後,如何科學地組織和存儲數據,如何高效獲取和維護數據成了關鍵

這就用到了一個系統軟件---數據庫管理系統

如MySQL、Oracle、SQLite、Access、MS SQL Server

mysql主要用於大型門戶,例如搜狗、新浪等,它主要的優點就是開放源代碼,由於開放源代碼這個數據庫是免費的,他如今是甲骨文公司的產品。
oracle主要用於銀行、鐵路、飛機場等。該數據庫功能強大,軟件費用高。也是甲骨文公司的產品。
sql server是微軟公司的產品,主要應用於大中型企業,如聯想、方正等。

4 數據庫服務器、數據管理系統、數據庫、表與記錄的關係(重點理解!!!)

記錄:1 劉海龍  324245234 22(多個字段的信息組成一條記錄,即文件中的一行內容)

表:student,scholl,class_list(即文件)

數據庫:oldboy_stu(即文件夾)

數據庫管理系統:如mysql(是一個軟件)

數據庫服務器:一臺計算機(對內存要求比較高)

總結:

    數據庫服務器-:運行數據庫管理軟件

    數據庫管理軟件:管理-數據庫

    數據庫:即文件夾,用來組織文件/表

    表:即文件,用來存放多行內容/多條記錄

5 數據庫管理技術的發展歷程(瞭解)

一 人工管理階段

20世紀50年代中期之前,計算機主要用於科學計算。

當時的硬件水平:外存只有紙帶、卡片、磁帶,沒有磁盤等直接存取的存儲設備

當時的軟件情況:沒有操做系統,沒有管理數據的軟件,數據的處理方式是批處理。

人工管理數據具備如下特色:

1 數據不保存:計算機主要用於科學計算,數據臨時用,臨時輸入,不保存

2 應用程序管理數據:數據要有應用程序本身管理,應用程序須要處理數據的邏輯+物理結構,開發負擔很重

3 數據不共享:一組數據只對應一個程序,多個程序之間涉及相同數據時,必須各自定義,形成數據大量冗餘

4 數據不具備獨立性:數據的邏輯結構或物理結構發生變化後,必須對應用程序作出相應的修改,開發負擔進一步加大

二 文件系統階段

20世紀50年代後期到60年代中期

硬件水平:有了磁盤、磁鼓等可直接存取的存儲設備

軟件水平:有了操做系統,而且操做系統中已經有了專門的數據管理軟件,即文件系統;處理方式上不只有了批處理,並且可以聯機實時處理

文件系統管理數據具備如下優勢:

1 數據能夠長期保存:計算機大量用於數據處理,於是數據須要長期保存,進行增刪改查操做

2 由文件系統管理數據:文件系統這個軟件,把數據組織成相對獨立的數據文件,利用按文件名,按記錄進行存取。實現了記錄內的結構性,但總體無結構。而且程序與數據之間由文件系統提供存取方法進行轉換,是應用程序與數據之間有了必定的獨立性,程序員能夠沒必要過多考慮物理細節。

文件系統管理數據具備如下缺點:

1 數據共享性差,冗餘度大:一個文件對應一個應用程序,不一樣應用有相同數據時,也必須創建各自的文件,不能共享相同的數據,形成數據冗餘,浪費空間,且相同的數據重複存儲,各自管理,容易形成數據不一致性

2 數據獨立性差:一旦數據的邏輯結構改變,必須修改應用程序,修改文件結構的定義。應用程序的改變,也將引發文件的數據結構的改變。所以數據與程序之間缺少獨立性。可見,文件系統仍然是一個不具備彈性的無結構的數據集合,即文件之間是孤立的,不能反映現實世界事物之間的內存聯繫。

三 數據系統階段

20世紀60年代後期以來,計算機用於管理的規模愈來愈大,應用愈來愈普遍,數據量急劇增加,同時多種應用,多種語言互相覆蓋地共享數據結合要求愈來愈強烈

硬件水平:有了大容量磁盤,硬件架構降低

軟件水平:軟件價格上升(開發效率必須提高,必須將程序員從數據管理中解放出來),分佈式的概念盛行。

數據庫系統的特色:

1 數據結構化(如上圖odboy_stu)

2 數據共享,冗餘度低,易擴充

3 數據獨立性高

4 數據由DBMS統一管理和控制

  a:數據的安全性保護

  b:數據的完整性檢查

  c:併發控制

  d:數據庫恢復

三 mysql介紹

MySQL是一個關係型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下公司。MySQL 最流行的關係型數據庫管理系統,在 WEB 應用方面MySQL是最好的 RDBMS (Relational Database Management System,關係數據庫管理系統) 應用軟件之一。

mysql是什麼

#mysql就是一個基於socket編寫的C/S架構的軟件
#客戶端軟件
  mysql自帶:如mysql命令,mysqldump命令等
  python模塊:如pymysql

數據庫管理軟件分類

#分兩大類:
  關係型:如sqllite,db2,oracle,access,sql server,MySQL,注意:sql語句通用
  非關係型:mongodb,redis,memcache

#能夠簡單的理解爲:
    關係型數據庫須要有表結構
    非關係型數據庫是key-value存儲的,沒有表結構

四 下載安裝

Linux版本

#二進制rpm包安裝
yum -y install mysql-server mysql

源碼安裝mysql

1.解壓tar包
cd /software
tar -xzvf mysql-5.6.21-linux-glibc2.5-x86_64.tar.gz
mv mysql-5.6.21-linux-glibc2.5-x86_64 mysql-5.6.21

2.添加用戶與組
groupadd mysql
useradd -r -g mysql mysql
chown -R mysql:mysql mysql-5.6.21

3.安裝數據庫
su mysql
cd mysql-5.6.21/scripts
./mysql_install_db --user=mysql --basedir=/software/mysql-5.6.21 --datadir=/software/mysql-5.6.21/data

4.配置文件
cd /software/mysql-5.6.21/support-files
cp my-default.cnf /etc/my.cnf
cp mysql.server /etc/init.d/mysql
vim /etc/init.d/mysql   #若mysql的安裝目錄是/usr/local/mysql,則可省略此步
修改文件中的兩個變動值
basedir=/software/mysql-5.6.21
datadir=/software/mysql-5.6.21/data

5.配置環境變量
vim /etc/profile
export MYSQL_HOME="/software/mysql-5.6.21"
export PATH="$PATH:$MYSQL_HOME/bin"
source /etc/profile

6.添加自啓動服務
chkconfig --add mysql
chkconfig mysql on

7.啓動mysql
service mysql start

8.登陸mysql及改密碼與配置遠程訪問
mysqladmin -u root password 'your_password'     #修改root用戶密碼
mysql -u root -p     #登陸mysql,須要輸入密碼
mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_password' WITH GRANT OPTION;     #容許root用戶遠程訪問
mysql>FLUSH PRIVILEGES;     #刷新權限

源碼安裝mariadb

1. 解壓
tar zxvf  mariadb-5.5.31-linux-x86_64.tar.gz   
mv mariadb-5.5.31-linux-x86_64 /usr/local/mysql //必需這樣,不少腳本或可執行程序都會直接訪問這個目錄

2. 權限
groupadd mysql             //增長 mysql 屬組 
useradd -g mysql mysql     //增長 mysql 用戶 並歸於mysql 屬組 
chown mysql:mysql -Rf  /usr/local/mysql    // 設置 mysql 目錄的用戶及用戶組歸屬。 
chmod +x -Rf /usr/local/mysql    //賜予可執行權限 

3. 拷貝配置文件
cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf     //複製默認mysql配置 文件到/etc目錄 

4. 初始化
/usr/local/mysql/scripts/mysql_install_db --user=mysql          //初始化數據庫 
cp  /usr/local/mysql/support-files/mysql.server    /etc/init.d/mysql    //複製mysql服務程序 到系統目錄 
chkconfig  mysql on     //添加mysql 至系統服務並設置爲開機啓動 
service  mysql  start  //啓動mysql

5. 環境變量配置
vim /etc/profile   //編輯profile,將mysql的可執行路徑加入系統PATH
export PATH=/usr/local/mysql/bin:$PATH 
source /etc/profile  //使PATH生效。

6. 帳號密碼
mysqladmin -u root password 'yourpassword' //設定root帳號及密碼
mysql -u root -p  //使用root用戶登陸mysql
use mysql  //切換至mysql數據庫。
select user,host,password from user; //查看系統權限
drop user ''@'localhost'; //刪除不安全的帳戶
drop user root@'::1';
drop user root@127.0.0.1;
select user,host,password from user; //再次查看系統權限,確保不安全的帳戶均被刪除。
flush privileges;  //刷新權限

7. 一些必要的初始配置
1)修改字符集爲UTF8
vi /etc/my.cnf
在[client]下面添加 default-character-set = utf8
在[mysqld]下面添加 character_set_server = utf8
2)增長錯誤日誌
vi /etc/my.cnf
在[mysqld]下面添加:
log-error = /usr/local/mysql/log/error.log
general-log-file = /usr/local/mysql/log/mysql.log
3) 設置爲不區分大小寫,linux下默認會區分大小寫。
vi /etc/my.cnf
在[mysqld]下面添加:
lower_case_table_name=1

修改完重啓:#service  mysql  restart

Window版本

安裝

#一、下載:MySQL Community Server 5.7.16
http://dev.mysql.com/downloads/mysql/

#二、解壓
若是想要讓MySQL安裝在指定目錄,那麼就將解壓後的文件夾移動到指定目錄,如:C:\mysql-5.7.16-winx64

#三、添加環境變量
【右鍵計算機】--》【屬性】--》【高級系統設置】--》【高級】--》【環境變量】--》【在第二個內容框中找到 變量名爲Path 的一行,雙擊】 --> 【將MySQL的bin目錄路徑追加到變值值中,用 ; 分割】
 
#四、初始化
mysqld --initialize-insecure

#五、啓動MySQL服務
mysqld # 啓動MySQL服務

#六、啓動MySQL客戶端並鏈接MySQL服務
mysql -u root -p # 鏈接MySQL服務器

將MySQL服務製做成windows服務

上一步解決了一些問題,但不夠完全,由於在執行【mysqd】啓動MySQL服務器時,當前終端會被hang住,那麼作一下設置便可解決此問題:



注意:--install前,必須用mysql啓動命令的絕對路徑
# 製做MySQL的Windows服務,在終端執行此命令:
"c:\mysql-5.7.16-winx64\bin\mysqld" --install
 
# 移除MySQL的Windows服務,在終端執行此命令:
"c:\mysql-5.7.16-winx64\bin\mysqld" --remove



註冊成服務以後,之後再啓動和關閉MySQL服務時,僅需執行以下命令:
# 啓動MySQL服務
net start mysql
 
# 關閉MySQL服務
net stop mysql

五 mysql軟件基本管理

1. 啓動查看

linux平臺下查看

[root@egon ~]# systemctl start mariadb #啓動
[root@egon ~]# systemctl enable mariadb #設置開機自啓動
Created symlink from /etc/systemd/system/multi-user.target.wants/mariadb.service to /usr/lib/systemd/system/mariadb.service.
[root@egon ~]# ps aux |grep mysqld |grep -v grep #查看進程,mysqld_safe爲啓動mysql的腳本文件,內部調用mysqld命令
mysql     3329  0.0  0.0 113252  1592 ?        Ss   16:19   0:00 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
mysql     3488  0.0  2.3 839276 90380 ?        Sl   16:19   0:00 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log --pid-file=/var/run/mariadb/mariadb.pid --socket=/var/lib/mysql/mysql.sock
[root@egon ~]# netstat -an |grep 3306 #查看端口
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN  
[root@egon ~]# ll -d /var/lib/mysql #權限不對,啓動不成功,注意user和group
drwxr-xr-x 5 mysql mysql 4096 Jul 20 16:28 /var/lib/mysql

You must reset your password using ALTER USER statement before executing this statement.

安裝完mysql 以後,登錄之後,無論運行任何命令,老是提示這個
mac mysql error You must reset your password using ALTER USER statement before executing this statement.
解決方法:
step 1: SET PASSWORD = PASSWORD('your new password');
step 2: ALTER USER 'root'@'localhost' PASSWORD EXPIRE NEVER;
step 3: flush privileges;

2. 登陸,設置密碼

初始狀態下,管理員root,密碼爲空,默認只容許從本機登陸localhost
設置密碼
[root@egon ~]# mysqladmin -uroot password "123"        設置初始密碼 因爲原密碼爲空,所以-p能夠不用
[root@egon ~]# mysqladmin -uroot -p"123" password "456"        修改mysql密碼,由於已經有密碼了,因此必須輸入原密碼才能設置新密碼

命令格式:
[root@egon ~]# mysql -h172.31.0.2 -uroot -p456
[root@egon ~]# mysql -uroot -p
[root@egon ~]# mysql                    以root用戶登陸本機,密碼爲空

3. 忘記密碼

linux平臺下,破解密碼的兩種方式

方法一:刪除受權庫mysql,從新初始化

[root@egon ~]# rm -rf /var/lib/mysql/mysql #全部受權信息所有丟失!!!
[root@egon ~]# systemctl restart mariadb
[root@egon ~]# mysql

方法二:啓動時,跳過受權庫

[root@egon ~]# vim /etc/my.cnf    #mysql主配置文件
[mysqld]
skip-grant-table
[root@egon ~]# systemctl restart mariadb
[root@egon ~]# mysql
MariaDB [(none)]> update mysql.user set password=password("123") where user="root" and host="localhost";
MariaDB [(none)]> flush privileges;
MariaDB [(none)]> \q
[root@egon ~]# #打開/etc/my.cnf去掉skip-grant-table,而後重啓
[root@egon ~]# systemctl restart mariadb
[root@egon ~]# mysql -u root -p123 #以新密碼登陸

windows平臺下,5.7版本mysql,破解密碼的兩種方式:

方法一:

#1 關閉mysql
#2 在cmd中執行:mysqld --skip-grant-tables
#3 在cmd中執行:mysql
#4 執行以下sql:
update mysql.user set authentication_string=password('') where user = 'root';
flush privileges;

#5 tskill mysqld #或taskkill -f /PID 7832
#6 從新啓動mysql

方法二:

#1. 關閉mysql,能夠用tskill mysqld將其殺死
#2. 在解壓目錄下,新建mysql配置文件my.ini
#3. my.ini內容,指定
[mysqld]
skip-grant-tables

#4.啓動mysqld
#5.在cmd裏直接輸入mysql登陸,而後操做
update mysql.user set authentication_string=password('') where user='root and host='localhost';

flush privileges;

#6.註釋my.ini中的skip-grant-tables,而後啓動myqsld,而後就能夠以新密碼登陸了

4. 在windows下,爲mysql服務指定配置文件

強調:配置文件中的註釋能夠有中文,可是配置項中不能出現中文

my.ini

#在mysql的解壓目錄下,新建my.ini,而後配置
#1. 在執行mysqld命令時,下列配置會生效,即mysql服務啓動時生效
[mysqld]
;skip-grant-tables
port=3306
character_set_server=utf8
default-storage-engine=innodb
innodb_file_per_table=1


#解壓的目錄
basedir=E:\mysql-5.7.19-winx64
#data目錄
datadir=E:\my_data #在mysqld --initialize時,就會將初始數據存入此處指定的目錄,在初始化以後,啓動mysql時,就會去這個目錄裏找數據



#2. 針對客戶端命令的全局配置,當mysql客戶端命令執行時,下列配置生效
[client]
port=3306
default-character-set=utf8
user=root
password=123

#3. 只針對mysql這個客戶端的配置,2中的是全局配置,而此處的則是隻針對mysql這個命令的局部配置
[mysql]
;port=3306
;default-character-set=utf8
user=egon
password=4573


#!!!若是沒有[mysql],則用戶在執行mysql命令時的配置以[client]爲準

5. 統一字符編碼

#1. 修改配置文件
[mysqld]
default-character-set=utf8 
[client]
default-character-set=utf8 
[mysql]
default-character-set=utf8

#mysql5.5以上:修改方式有所改動
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8

#2. 重啓服務
#3. 查看修改結果:
\s
show variables like '%char%'

六 初識sql語句

有了mysql這個數據庫軟件,就能夠將程序員從對數據的管理中解脫出來,專一於對程序邏輯的編寫

mysql服務端軟件即mysqld幫咱們管理好文件夾以及文件,前提是做爲使用者的咱們,須要下載mysql的客戶端,或者其餘模塊來鏈接到mysqld,而後使用mysql軟件規定的語法格式去提交本身命令,實現對文件夾或文件的管理。該語法即sql(Structured Query Language 即結構化查詢語言)

SQL語言主要用於存取數據、查詢數據、更新數據和管理關係數據庫系統,SQL語言由IBM開發。SQL語言分爲3種類型:
#一、DDL語句    數據庫定義語言: 數據庫、表、視圖、索引、存儲過程,例如CREATE DROP ALTER
#二、DML語句    數據庫操縱語言: 插入數據INSERT、刪除數據DELETE、更新數據UPDATE、查詢數據SELECT
#三、DCL語句    數據庫控制語言: 例如控制用戶的訪問權限GRANT、REVOKE

view code:

#1. 操做文件夾
        增:create database db1 charset utf8;
        查:show databases;
        改:alter database db1 charset latin1;
        刪除: drop database db1;


#2. 操做文件
    先切換到文件夾下:use db1
        增:create table t1(id int,name char);
        查:show tables
        改:alter table t1 modify name char(3);
              alter table t1 change name name1 char(2);
        刪:drop table t1;
    

#3. 操做文件中的內容/記錄
        增:insert into t1 values(1,'egon1'),(2,'egon2'),(3,'egon3');
        查:select * from t1;
        改:update t1 set name='sb' where id=2;
        刪:delete from t1 where id=1;

        清空表:
            delete from t1; #若是有自增id,新增的數據,仍然是以刪除前的最後同樣做爲起始。
            truncate table t1;數據量大,刪除速度比上一條快,且直接從零開始,

            auto_increment 表示:自增
            primary key 表示:約束(不能重複且不能爲空);加速查找

mysql二:庫操做

一 系統數據庫

information_schema: 虛擬庫,不佔用磁盤空間,存儲的是數據庫啓動後的一些參數,如用戶表信息、列信息、權限信息、字符信息等
performance_schema: MySQL 5.5開始新增一個數據庫:主要用於收集數據庫服務器性能參數,記錄處理查詢請求時發生的各類事件、鎖等現象 
mysql: 受權庫,主要存儲系統用戶的權限信息
test: MySQL數據庫系統自動建立的測試數據庫

二 建立數據庫

1 語法(help create database)

CREATE DATABASE 數據庫名 charset utf8;

2 數據庫命名規則:

能夠由字母、數字、下劃線、@、#、$
區分大小寫
惟一性
不能使用關鍵字如 create select
不能單獨使用數字
最長128位

三 數據庫相關操做

1 查看數據庫
show databases;
show create database db1;
select database();

2 選擇數據庫
USE 數據庫名

3 刪除數據庫
DROP DATABASE 數據庫名;

4 修改數據庫
alter database db1 charset utf8;

mysql三:表操做

一 存儲引擎介紹

存儲引擎即表類型,mysql根據不一樣的表類型會有不一樣的處理機制

詳見:http://www.cnblogs.com/linhaifeng/articles/7213670.html

二 表介紹

表至關於文件,表中的一條記錄就至關於文件的一行內容,不一樣的是,表中的一條記錄有對應的標題,稱爲表的字段

id,name,qq,age稱爲字段,其他的,一行內容稱爲一條記錄

三 建立表

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

#注意:
1. 在同一張表中,字段名是不能相同
2. 寬度和約束條件可選
3. 字段名和類型是必須的

view code:

MariaDB [(none)]> create database db1 charset utf8;

MariaDB [(none)]> use db1;

MariaDB [db1]> create table t1(  
    -> id int, 
    -> name varchar(50),
    -> sex enum('male','female'),
    -> age int(3)
    -> );

MariaDB [db1]> show tables; #查看db1庫下全部表名

MariaDB [db1]> desc t1;
+-------+-----------------------+------+-----+---------+-------+
| Field | Type                  | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id    | int(11)               | YES  |     | NULL    |       |
| name  | varchar(50)           | YES  |     | NULL    |       |
| sex   | enum('male','female') | YES  |     | NULL    |       |
| age   | int(3)                | YES  |     | NULL    |       |
+-------+-----------------------+------+-----+---------+-------+

MariaDB [db1]> select id,name,sex,age from t1;
Empty set (0.00 sec)

MariaDB [db1]> select * from t1;
Empty set (0.00 sec)

MariaDB [db1]> select id,name from t1;
Empty set (0.00 sec)

往表中插入數據

MariaDB [db1]> insert into t1 values
    -> (1,'egon',18,'male'),
    -> (2,'alex',81,'female')
    -> ;
MariaDB [db1]> select * from t1;
+------+------+------+--------+
| id   | name | age  | sex    |
+------+------+------+--------+
|    1 | egon |   18 | male   |
|    2 | alex |   81 | female |
+------+------+------+--------+



MariaDB [db1]> insert into t1(id) values 
    -> (3),
    -> (4);
MariaDB [db1]> select * from t1;
+------+------+------+--------+
| id   | name | age  | sex    |
+------+------+------+--------+
|    1 | egon |   18 | male   |
|    2 | alex |   81 | female |
|    3 | NULL | NULL | NULL   |
|    4 | NULL | NULL | NULL   |
+------+------+------+--------+

注意注意注意:表中的最後一個字段不要加逗號

四 查看錶結構

MariaDB [db1]> describe t1; #查看錶結構,可簡寫爲desc 表名
+-------+-----------------------+------+-----+---------+-------+
| Field | Type                  | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
| id    | int(11)               | YES  |     | NULL    |       |
| name  | varchar(50)           | YES  |     | NULL    |       |
| sex   | enum('male','female') | YES  |     | NULL    |       |
| age   | int(3)                | YES  |     | NULL    |       |
+-------+-----------------------+------+-----+---------+-------+


MariaDB [db1]> show create table t1\G; #查看錶詳細結構,可加\G

五 數據類型

http://www.cnblogs.com/linhaifeng/articles/7233411.html

六 表完整性約束

http://www.cnblogs.com/linhaifeng/articles/7238814.html

七 修改表ALTER TABLE

語法:
1. 修改表名
      ALTER TABLE 表名 
                          RENAME 新表名;

2. 增長字段
      ALTER TABLE 表名
                          ADD 字段名  數據類型 [完整性約束條件…],
                          ADD 字段名  數據類型 [完整性約束條件…];
      ALTER TABLE 表名
                          ADD 字段名  數據類型 [完整性約束條件…]  FIRST;
      ALTER TABLE 表名
                          ADD 字段名  數據類型 [完整性約束條件…]  AFTER 字段名;
                            
3. 刪除字段
      ALTER TABLE 表名 
                          DROP 字段名;

4. 修改字段
      ALTER TABLE 表名 
                          MODIFY  字段名 數據類型 [完整性約束條件…];
      ALTER TABLE 表名 
                          CHANGE 舊字段名 新字段名 舊數據類型 [完整性約束條件…];
      ALTER TABLE 表名 
                          CHANGE 舊字段名 新字段名 新數據類型 [完整性約束條件…];

示例:

示例:
1. 修改存儲引擎
mysql> alter table service 
    -> engine=innodb;

2. 添加字段
mysql> alter table student10
    -> add name varchar(20) not null,
    -> add age int(3) not null default 22;
    
mysql> alter table student10
    -> add stu_num varchar(10) not null after name;                //添加name字段以後

mysql> alter table student10                        
    -> add sex enum('male','female') default 'male' first;          //添加到最前面

3. 刪除字段
mysql> alter table student10
    -> drop sex;

mysql> alter table service
    -> drop mac;

4. 修改字段類型modify
mysql> alter table student10
    -> modify age int(3);
mysql> alter table student10
    -> modify id int(11) not null primary key auto_increment;    //修改成主鍵

5. 增長約束(針對已有的主鍵增長auto_increment)
mysql> alter table student10 modify id int(11) not null primary key auto_increment;
ERROR 1068 (42000): Multiple primary key defined

mysql> alter table student10 modify id int(11) not null auto_increment;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

6. 對已經存在的表增長複合主鍵
mysql> alter table service2
    -> add primary key(host_ip,port);        

7. 增長主鍵
mysql> alter table student1
    -> modify name varchar(10) not null primary key;

8. 增長主鍵和自動增加
mysql> alter table student1
    -> modify id int not null primary key auto_increment;

9. 刪除主鍵
a. 刪除自增約束
mysql> alter table student10 modify id int(11) not null; 

b. 刪除主鍵
mysql> alter table student10                                 
    -> drop primary key;

八 複製表

複製表結構+記錄 (key不會複製: 主鍵、外鍵和索引)
mysql> create table new_service select * from service;

只複製表結構
mysql> select * from service where 1=2;        //條件爲假,查不到任何記錄
Empty set (0.00 sec)
mysql> create table new1_service select * from service where 1=2;  
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create table t4 like employees;

mysql四:數據操做

一 介紹

MySQL數據操做: DML

========================================================

在MySQL管理軟件中,能夠經過SQL語句中的DML語言來實現數據的操做,包括

  1. 使用INSERT實現數據的插入
  2. UPDATE實現數據的更新
  3. 使用DELETE實現數據的刪除
  4. 使用SELECT查詢數據以及。

========================================================

本節內容包括:

插入數據
更新數據
刪除數據
查詢數據

二 插入數據INSERT

1. 插入完整數據(順序插入)
    語法一:
    INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n);

    語法二:
    INSERT INTO 表名 VALUES (值1,值2,值3…值n);

2. 指定字段插入數據
    語法:
    INSERT INTO 表名(字段1,字段2,字段3…) VALUES (值1,值2,值3…);

3. 插入多條記錄
    語法:
    INSERT INTO 表名 VALUES
        (值1,值2,值3…值n),
        (值1,值2,值3…值n),
        (值1,值2,值3…值n);
        
4. 插入查詢結果
    語法:
    INSERT INTO 表名(字段1,字段2,字段3…字段n) 
                    SELECT (字段1,字段2,字段3…字段n) FROM 表2
                    WHERE …;

三 更新數據UPDATE

語法:
    UPDATE 表名 SET
        字段1=值1,
        字段2=值2,
        WHERE CONDITION;

示例:
    UPDATE mysql.user SET password=password(‘123’) 
        where user=’root’ and host=’localhost’;

四 刪除數據DELETE

語法:
    DELETE FROM 表名 
        WHERE CONITION;

示例:
    DELETE FROM mysql.user 
        WHERE password=’’;

練習:
    更新MySQL root用戶密碼爲mysql123
    刪除除從本地登陸的root用戶之外的全部用戶

五 查詢數據SELECT

單表查詢:http://www.cnblogs.com/linhaifeng/articles/7267592.html

多表查詢:http://www.cnblogs.com/linhaifeng/articles/7267596.html

六 權限管理

#受權表
user #該表放行的權限,針對:全部數據,全部庫下全部表,以及表下的全部字段
db #該表放行的權限,針對:某一數據庫,該數據庫下的全部表,以及表下的全部字段
tables_priv #該表放行的權限。針對:某一張表,以及該表下的全部字段
columns_priv #該表放行的權限,針對:某一個字段

#按圖解釋:
user:放行db1,db2及其包含的全部
db:放行db1,及其db1包含的全部
tables_priv:放行db1.table1,及其該表包含的全部
columns_prive:放行db1.table1.column1,只放行該字段

 

mysql五:索引原理與慢查詢優化

一 介紹

爲什麼要有索引?

通常的應用系統,讀寫比例在10:1左右,並且插入操做和通常的更新操做不多出現性能問題,在生產環境中,咱們遇到最多的,也是最容易出問題的,仍是一些複雜的查詢操做,所以對查詢語句的優化顯然是重中之重。提及加速查詢,就不得不提到索引了。

什麼是索引?

索引在MySQL中也叫作「鍵」,是存儲引擎用於快速找到記錄的一種數據結構。索引對於良好的性能
很是關鍵,尤爲是當表中的數據量愈來愈大時,索引對於性能的影響愈發重要。
索引優化應該是對查詢性能優化最有效的手段了。索引可以輕易將查詢性能提升好幾個數量級。
索引至關於字典的音序表,若是要查某個字,若是不使用音序表,則須要從幾百頁中逐頁去查。

                      30

        10                          40

   5         15               35          66

1    6    11   19          21   39     55    100

你是否對索引存在誤解?

索引是應用程序設計和開發的一個重要方面。若索引太多,應用程序的性能可能會受到影響。而索引太少,對查詢性能又會產生影響,要找到一個平衡點,這對應用程序的性能相當重要。一些開發人員老是在過後纔想起添加索引----我一直認爲,這源於一種錯誤的開發模式。若是知道數據的使用,從一開始就應該在須要處添加索引。開發人員每每對數據庫的使用停留在應用的層面,好比編寫SQL語句、存儲過程之類,他們甚至可能不知道索引的存在,或認爲過後讓相關DBA加上便可。DBA每每不夠了解業務的數據流,而添加索引須要經過監控大量的SQL語句進而從中找到問題,這個步驟所需的時間確定是遠大於初始添加索引所需的時間,而且可能會遺漏一部分的索引。固然索引也並非越多越好,我曾經遇到過這樣一個問題:某臺MySQL服務器iostat顯示磁盤使用率一直處於100%,通過分析後發現是因爲開發人員添加了太多的索引,在刪除一些沒必要要的索引以後,磁盤使用率立刻降低爲20%。可見索引的添加也是很是有技術含量的。

二 索引的原理

一 索引原理

索引的目的在於提升查詢效率,與咱們查閱圖書所用的目錄是一個道理:先定位到章,而後定位到該章下的一個小節,而後找到頁數。類似的例子還有:查字典,查火車車次,飛機航班等

本質都是:經過不斷地縮小想要獲取數據的範圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是說,有了這種索引機制,咱們能夠老是用同一種查找方式來鎖定數據。

數據庫也是同樣,但顯然要複雜的多,由於不只面臨着等值查詢,還有範圍查詢(>、<、between、in)、模糊查詢(like)、並集查詢(or)等等。數據庫應該選擇怎麼樣的方式來應對全部的問題呢?咱們回想字典的例子,能不能把數據分紅段,而後分段查詢呢?最簡單的若是1000條數據,1到100分紅第一段,101到200分紅第二段,201到300分紅第三段......這樣查第250條數據,只要找第三段就能夠了,一會兒去除了90%的無效數據。但若是是1千萬的記錄呢,分紅幾段比較好?稍有算法基礎的同窗會想到搜索樹,其平均複雜度是lgN,具備不錯的查詢性能。但這裏咱們忽略了一個關鍵的問題,複雜度模型是基於每次相同的操做成原本考慮的。而數據庫實現比較複雜,一方面數據是保存在磁盤上的,另一方面爲了提升性能,每次又能夠把部分數據讀入內存來計算,由於咱們知道訪問磁盤的成本大概是訪問內存的十萬倍左右,因此簡單的搜索樹難以知足複雜的應用場景。

二 磁盤IO與預讀

前面提到了訪問磁盤,那麼這裏先簡單介紹一下磁盤IO和預讀,磁盤讀取數據靠的是機械運動,每次讀取數據花費的時間能夠分爲尋道時間、旋轉延遲、傳輸時間三個部分,尋道時間指的是磁臂移動到指定磁道所須要的時間,主流磁盤通常在5ms如下;旋轉延遲就是咱們常常據說的磁盤轉速,好比一個磁盤7200轉,表示每分鐘能轉7200次,也就是說1秒鐘能轉120次,旋轉延遲就是1/120/2 = 4.17ms;傳輸時間指的是從磁盤讀出或將數據寫入磁盤的時間,通常在零點幾毫秒,相對於前兩個時間能夠忽略不計。那麼訪問一次磁盤的時間,即一次磁盤IO的時間約等於5+4.17 = 9ms左右,聽起來還挺不錯的,但要知道一臺500 -MIPS(Million Instructions Per Second)的機器每秒能夠執行5億條指令,由於指令依靠的是電的性質,換句話說執行一次IO的時間能夠執行約450萬條指令,數據庫動輒十萬百萬乃至千萬級數據,每次9毫秒的時間,顯然是個災難。下圖是計算機硬件延遲的對比圖,供你們參考:

 

考慮到磁盤IO是很是高昂的操做,計算機操做系統作了一些優化,當一次IO時,不光把當前磁盤地址的數據,而是把相鄰的數據也都讀取到內存緩衝區內,由於局部預讀性原理告訴咱們,當計算機訪問一個地址的數據的時候,與其相鄰的數據也會很快被訪問到。每一次IO讀取的數據咱們稱之爲一頁(page)。具體一頁有多大數據跟操做系統有關,通常爲4k或8k,也就是咱們讀取一頁內的數據時候,實際上才發生了一次IO,這個理論對於索引的數據結構設計很是有幫助。

三 索引的數據結構

前面講了索引的基本原理,數據庫的複雜性,又講了操做系統的相關知識,目的就是讓你們瞭解,任何一種數據結構都不是憑空產生的,必定會有它的背景和使用場景,咱們如今總結一下,咱們須要這種數據結構可以作些什麼,其實很簡單,那就是:每次查找數據時把磁盤IO次數控制在一個很小的數量級,最好是常數數量級。那麼咱們就想到若是一個高度可控的多路搜索樹是否能知足需求呢?就這樣,b+樹應運而生(B+樹是經過二叉查找樹,再由平衡二叉樹,B樹演化而來)。

如上圖,是一顆b+樹,關於b+樹的定義能夠參見B+樹,這裏只說一些重點,淺藍色的塊咱們稱之爲一個磁盤塊,能夠看到每一個磁盤塊包含幾個數據項(深藍色所示)和指針(黃色所示),如磁盤塊1包含數據項17和35,包含指針P一、P二、P3,P1表示小於17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大於35的磁盤塊。真實的數據存在於葉子節點即三、五、九、十、1三、1五、2八、2九、3六、60、7五、7九、90、99。非葉子節點只不存儲真實的數據,只存儲指引搜索方向的數據項,如1七、35並不真實存在於數據表中。

###b+樹的查找過程
如圖所示,若是要查找數據項29,那麼首先會把磁盤塊1由磁盤加載到內存,此時發生一次IO,在內存中用二分查找肯定29在17和35之間,鎖定磁盤塊1的P2指針,內存時間由於很是短(相比磁盤的IO)能夠忽略不計,經過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO,29在26和30之間,鎖定磁盤塊3的P2指針,經過指針加載磁盤塊8到內存,發生第三次IO,同時內存中作二分查找找到29,結束查詢,總計三次IO。真實的狀況是,3層的b+樹能夠表示上百萬的數據,若是上百萬的數據查找只須要三次IO,性能提升將是巨大的,若是沒有索引,每一個數據項都要發生一次IO,那麼總共須要百萬次的IO,顯然成本很是很是高。

###b+樹性質
1.索引字段要儘可能的小:經過上面的分析,咱們知道IO次數取決於b+數的高度h,假設當前數據表的數據爲N,每一個磁盤塊的數據項的數量是m,則有h=㏒(m+1)N,當數據量N必定的狀況下,m越大,h越小;而m = 磁盤塊的大小 / 數據項的大小,磁盤塊的大小也就是一個數據頁的大小,是固定的,若是數據項佔的空間越小,數據項的數量越多,樹的高度越低。這就是爲何每一個數據項,即索引字段要儘可能的小,好比int佔4字節,要比bigint8字節少一半。這也是爲何b+樹要求把真實的數據放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的數據項會大幅度降低,致使樹增高。當數據項等於1時將會退化成線性表。
2.索引的最左匹配特性:當b+樹的數據項是複合的數據結構,好比(name,age,sex)的時候,b+數是按照從左到右的順序來創建搜索樹的,好比當(張三,20,F)這樣的數據來檢索的時候,b+樹會優先比較name來肯定下一步的所搜方向,若是name相同再依次比較age和sex,最後獲得檢索的數據;但當(20,F)這樣的沒有name的數據來的時候,b+樹就不知道下一步該查哪一個節點,由於創建搜索樹的時候name就是第一個比較因子,必需要先根據name來搜索才能知道下一步去哪裏查詢。好比當(張三,F)這樣的數據來檢索時,b+樹能夠用name來指定搜索方向,但下一個字段age的缺失,因此只能把名字等於張三的數據都找到,而後再匹配性別是F的數據了, 這個是很是重要的性質,即索引的最左匹配特性。

四 彙集索引與輔助索引

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

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

彙集索引與輔助索引相同的是:無論是彙集索引仍是輔助索引,其內部都是B+樹的形式,即高度是平衡的,葉子結點存放着全部的數據。

彙集索引與輔助索引不一樣的是:葉子結點存放的是不是一整行的信息

一、彙集索引

#InnoDB存儲引擎表示索引組織表,即表中數據按照主鍵順序存放。而彙集索引(clustered index)就是按照每張表的主鍵構造一棵B+樹,同時葉子結點存放的即爲整張表的行記錄數據,也將彙集索引的葉子結點稱爲數據頁。彙集索引的這個特性決定了索引組織表中數據也是索引的一部分。同B+樹數據結構同樣,每一個數據頁都經過一個雙向鏈表來進行連接。
    
#若是未定義主鍵,MySQL取第一個惟一索引(unique)並且只含非空列(NOT NULL)做爲主鍵,InnoDB使用它做爲聚簇索引。
    
#若是沒有這樣的列,InnoDB就本身產生一個這樣的ID值,它有六個字節,並且是隱藏的,使其做爲聚簇索引。

#因爲實際的數據頁只能按照一棵B+樹進行排序,所以每張表只能擁有一個彙集索引。在多少狀況下,查詢優化器傾向於採用彙集索引。由於彙集索引可以在B+樹索引的葉子節點上直接找到數據。此外因爲定義了數據的邏輯順序,彙集索引可以特別快地訪問針對範圍值得查詢。

彙集索引的好處之一:它對主鍵的排序查找和範圍查找速度很是快,葉子節點的數據就是用戶所要查詢的數據。如用戶須要查找一張表,查詢最後的10位用戶信息,因爲B+樹索引是雙向鏈表,因此用戶能夠快速找到最後一個數據頁,並取出10條記錄

view code:

#參照第六小結測試索引的準備階段來建立出表s1
mysql> desc s1; #最開始沒有主鍵
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   |     | NULL    |       |
| name   | varchar(20) | YES  |     | NULL    |       |
| gender | char(6)     | YES  |     | NULL    |       |
| email  | varchar(50) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> explain select * from s1 order by id desc limit 10; #Using filesort,須要二次排序
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+----------------+
|  1 | SIMPLE      | s1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 2633472 |   100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+----------------+
1 row in set, 1 warning (0.11 sec)

mysql> alter table s1 add primary key(id); #添加主鍵
Query OK, 0 rows affected (13.37 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select * from s1 order by id desc limit 10; #基於主鍵的彙集索引在建立完畢後就已經完成了排序,無需二次排序
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------+
|  1 | SIMPLE      | s1    | NULL       | index | NULL          | PRIMARY | 4       | NULL |   10 |   100.00 | NULL  |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.04 sec)

彙集索引的好處之二:範圍查詢(range query),即若是要查找主鍵某一範圍內的數據,經過葉子節點的上層中間節點就能夠獲得頁的範圍,以後直接讀取數據頁便可

view code:

mysql> alter table s1 drop primary key;
Query OK, 2699998 rows affected (24.23 sec)
Records: 2699998  Duplicates: 0  Warnings: 0

mysql> desc s1;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   |     | NULL    |       |
| name   | varchar(20) | YES  |     | NULL    |       |
| gender | char(6)     | YES  |     | NULL    |       |
| email  | varchar(50) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.12 sec)

mysql> explain select * from s1 where id > 1 and id < 1000000; #沒有彙集索引,預估須要檢索的rows數以下
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | s1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 2690100 |    11.11 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> alter table s1 add primary key(id);
Query OK, 0 rows affected (16.25 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select * from s1 where id > 1 and id < 1000000; #有彙集索引,預估須要檢索的rows數以下
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | s1    | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL | 1343355 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.09 sec)

二、輔助索引

表中除了彙集索引外其餘索引都是輔助索引(Secondary Index,也稱爲非彙集索引),與彙集索引的區別是:輔助索引的葉子節點不包含行記錄的所有數據。

葉子節點除了包含鍵值之外,每一個葉子節點中的索引行中還包含一個書籤(bookmark)。該書籤用來告訴InnoDB存儲引擎去哪裏能夠找到與索引相對應的行數據。

因爲InnoDB存儲引擎是索引組織表,所以InnoDB存儲引擎的輔助索引的書籤就是相應行數據的彙集索引鍵。以下圖

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

舉例來講,若是在一棵高度爲3的輔助索引樹種查找數據,那須要對這個輔助索引樹遍歷3次找到指定主鍵,若是彙集索引樹的高度一樣爲3,那麼還須要對彙集索引樹進行3次查找,最終找到一個完整的行數據所在的頁,所以一共須要6次邏輯IO訪問才能獲得最終的一個數據頁。

五 MySQL索引管理

一 功能

#1. 索引的功能就是加速查找
#2. mysql中的primary key,unique,聯合惟一也都是索引,這些索引除了加速查找之外,還有約束的功能

二 MySQL經常使用的索引

普通索引INDEX:加速查找

惟一索引:
    -主鍵索引PRIMARY KEY:加速查找+約束(不爲空、不能重複)
    -惟一索引UNIQUE:加速查找+約束(不能重複)

聯合索引:
    -PRIMARY KEY(id,name):聯合主鍵索引
    -UNIQUE(id,name):聯合惟一索引
    -INDEX(id,name):聯合普通索引

各個索引的應用場景

舉個例子來講,好比你在爲某商場作一個會員卡的系統。

這個系統有一個會員表
有下列字段:
會員編號 INT
會員姓名 VARCHAR(10)
會員身份證號碼 VARCHAR(18)
會員電話 VARCHAR(10)
會員住址 VARCHAR(50)
會員備註信息 TEXT

那麼這個 會員編號,做爲主鍵,使用 PRIMARY
會員姓名 若是要建索引的話,那麼就是普通的 INDEX
會員身份證號碼 若是要建索引的話,那麼能夠選擇 UNIQUE (惟一的,不容許重複)

#除此以外還有全文索引,即FULLTEXT
會員備註信息 , 若是須要建索引的話,能夠選擇全文搜索。
用於搜索很長一篇文章的時候,效果最好。
用在比較短的文本,若是就一兩行字的,普通的 INDEX 也能夠。
但其實對於全文搜索,咱們並不會使用MySQL自帶的該索引,而是會選擇第三方軟件如Sphinx,專門來作全文搜索。

#其餘的如空間索引SPATIAL,瞭解便可,幾乎不用

三 索引的兩大類型hash與btree

#咱們能夠在建立上述索引的時候,爲其指定索引類型,分兩類
hash類型的索引:查詢單條快,範圍查詢慢
btree類型的索引:b+樹,層數越多,數據量指數級增加(咱們就用它,由於innodb默認支持它)

#不一樣的存儲引擎支持的索引類型也不同
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 等索引;

四 建立/刪除索引的語法

#方法一:建立表時
      CREATE TABLE 表名 (
                字段名1  數據類型 [完整性約束條件…],
                字段名2  數據類型 [完整性約束條件…],
                [UNIQUE | FULLTEXT | SPATIAL ]   INDEX | KEY
                [索引名]  (字段名[(長度)]  [ASC |DESC]) 
                );


#方法二:CREATE在已存在的表上建立索引
        CREATE  [UNIQUE | FULLTEXT | SPATIAL ]  INDEX  索引名 
                     ON 表名 (字段名[(長度)]  [ASC |DESC]) ;


#方法三:ALTER TABLE在已存在的表上建立索引
        ALTER TABLE 表名 ADD  [UNIQUE | FULLTEXT | SPATIAL ] INDEX
                             索引名 (字段名[(長度)]  [ASC |DESC]) ;
                             
#刪除索引:DROP INDEX 索引名 ON 表名字;

示範:

#方式一
create table t1(
    id int,
    name char,
    age int,
    sex enum('male','female'),
    unique key uni_id(id),
    index ix_name(name) #index沒有key
);


#方式二
create index ix_age on t1(age);

#方式三
alter table t1 add index ix_sex(sex);

#查看
mysql> show create table t1;
| t1    | CREATE TABLE `t1` (
  `id` int(11) DEFAULT NULL,
  `name` char(1) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `sex` enum('male','female') DEFAULT NULL,
  UNIQUE KEY `uni_id` (`id`),
  KEY `ix_name` (`name`),
  KEY `ix_age` (`age`),
  KEY `ix_sex` (`sex`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

六 測試索引

一 準備

view code:

#1. 準備表
create table s1(
id int,
name varchar(20),
gender char(6),
email varchar(50)
);

#2. 建立存儲過程,實現批量插入記錄
delimiter $$ #聲明存儲過程的結束符號爲$$
create procedure auto_insert1()
BEGIN
    declare i int default 1;
    while(i<3000000)do
        insert into s1 values(i,'egon','male',concat('egon',i,'@oldboy'));
        set i=i+1;
    end while;
END$$ #$$結束
delimiter ; #從新聲明分號爲結束符號

#3. 查看存儲過程
show create procedure auto_insert1\G 

#4. 調用存儲過程
call auto_insert1();

二 在沒有索引的前提下測試查詢速度

#無索引:mysql根本就不知道究竟是否存在id等於333333333的記錄,只能把數據表從頭至尾掃描一遍,此時有多少個磁盤塊就須要進行多少IO操做,因此查詢速度很慢
mysql> select * from s1 where id=333333333;
Empty set (0.33 sec)

三 在表中已經存在大量數據的前提下,爲某個字段段創建索引,創建速度會很慢

四 在索引創建完畢後,以該字段爲查詢條件時,查詢速度提高明顯

PS:

1. mysql先去索引表裏根據b+樹的搜索原理很快搜索到id等於333333333的記錄不存在,IO大大下降,於是速度明顯提高

2. 咱們能夠去mysql的data目錄下找到該表,能夠看到佔用的硬盤空間多了

3. 須要注意,以下圖

五 總結

#1. 必定是爲搜索條件的字段建立索引,好比select * from s1 where id = 333;就須要爲id加上索引

#2. 在表中已經有大量數據的狀況下,建索引會很慢,且佔用硬盤空間,建完後查詢速度加快
好比create index idx on s1(id);會掃描表中全部的數據,而後以id爲數據項,建立索引結構,存放於硬盤的表中。
建完之後,再查詢就會很快了。

#3. 須要注意的是:innodb表的索引會存放於s1.ibd文件中,而myisam表的索引則會有單獨的索引文件table1.MYI

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

七 正確使用索引

一 索引未命中

並非說咱們建立了索引就必定會加快查詢速度,若想利用索引達到預想的提升查詢速度的效果,咱們在添加索引時,必須遵循如下問題

1 範圍問題,或者說條件不明確,條件中出現這些符號或關鍵字:>、>=、<、<=、!= 、between...and...、like、

大於號、小於號

不等於!=

between ...and...

like

2 儘可能選擇區分度高的列做爲索引,區分度的公式是count(distinct col)/count(*),表示字段不重複的比例,比例越大咱們掃描的記錄數越少,惟一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0,那可能有人會問,這個比例有什麼經驗值嗎?使用場景不一樣,這個值也很難肯定,通常須要join的字段咱們都要求是0.1以上,即平均1條掃描10條記錄

#先把表中的索引都刪除,讓咱們專心研究區分度的問題

#先把表中的索引都刪除,讓咱們專心研究區分度的問題
mysql> desc s1;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | YES  | MUL | NULL    |       |
| name   | varchar(20) | YES  |     | NULL    |       |
| gender | char(5)     | YES  |     | NULL    |       |
| email  | varchar(50) | YES  | MUL | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

mysql> drop index a on s1;
Query OK, 0 rows affected (0.20 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> drop index d on s1;
Query OK, 0 rows affected (0.18 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc s1;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | YES  |     | NULL    |       |
| name   | varchar(20) | YES  |     | NULL    |       |
| gender | char(5)     | YES  |     | NULL    |       |
| email  | varchar(50) | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

分析緣由

咱們編寫存儲過程爲表s1批量添加記錄,name字段的值均爲egon,也就是說name這個字段的區分度很低(gender字段也是同樣的,咱們稍後再搭理它)

回憶b+樹的結構,查詢的速度與樹的高度成反比,要想將樹的高低控制的很低,須要保證:在某一層內數據項均是按照從左到右,從小到大的順序依次排開,即左1<左2<左3<...

而對於區分度低的字段,沒法找到大小關係,由於值都是相等的,毫無疑問,還想要用b+樹存放這些等值的數據,只能增長樹的高度,字段的區分度越低,則樹的高度越高。極端的狀況,索引字段的值都同樣,那麼b+樹幾乎成了一根棍。本例中就是這種極端的狀況,name字段全部的值均爲'egon'

#如今咱們得出一個結論:爲區分度低的字段創建索引,索引樹的高度會很高,然而這具體會帶來什麼影響呢???

#1:若是條件是name='xxxx',那麼確定是能夠第一時間判斷出'xxxx'是不在索引樹中的(由於樹中全部的值均爲'egon’),因此查詢速度很快

#2:若是條件正好是name='egon',查詢時,咱們永遠沒法從樹的某個位置獲得一個明確的範圍,只能往下找,往下找,往下找。。。這與全表掃描的IO次數沒有多大區別,因此速度很慢

3 =和in能夠亂序,好比a = 1 and b = 2 and c = 3 創建(a,b,c)索引能夠任意順序,mysql的查詢優化器會幫你優化成索引能夠識別的形式

4 索引列不能參與計算,保持列「乾淨」,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,緣由很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,須要把全部元素都應用函數才能比較,顯然成本太大。因此語句應該寫成create_time = unix_timestamp(’2014-05-29’)

5 and/or

#一、and與or的邏輯
    條件1 and 條件2:全部條件都成立纔算成立,但凡要有一個條件不成立則最終結果不成立
    條件1 or 條件2:只要有一個條件成立則最終結果就成立

#二、and的工做原理
    條件:
        a = 10 and b = 'xxx' and c > 3 and d =4
    索引:
        製做聯合索引(d,a,b,c)
    工做原理:
        對於連續多個and:mysql會按照聯合索引,從左到右的順序找一個區分度高的索引字段(這樣即可以快速鎖定很小的範圍),加速查詢,即按照d—>a->b->c的順序

#三、or的工做原理
    條件:
        a = 10 or b = 'xxx' or c > 3 or d =4
    索引:
        製做聯合索引(d,a,b,c)
        
    工做原理:
        對於連續多個or:mysql會按照條件的順序,從左到右依次判斷,即a->b->c->d

在左邊條件成立可是索引字段的區分度低的狀況下(name與gender均屬於這種狀況),會依次往右找到一個區分度高的索引字段,加速查詢

通過分析,在條件爲name='egon' and gender='male' and id>333 and email='xxx'的狀況下,咱們徹底不必爲前三個條件的字段加索引,由於只能用上email字段的索引,前三個字段的索引反而會下降咱們的查詢效率

6 最左前綴匹配原則(詳見第八小節),很是重要的原則,對於組合索引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的順序能夠任意調整。

7 其餘狀況

view code:

- 使用函數
    select * from tb1 where reverse(email) = 'egon';
            
- 類型不一致
    若是列是字符串類型,傳入條件是必須用引號引發來,否則...
    select * from tb1 where email = 999;
    
#排序條件爲索引,則select字段必須也是索引字段,不然沒法命中
- order by
    select name from s1 order by email desc;
    當根據索引排序時候,select查詢的字段若是不是索引,則速度仍然很慢
    select email from s1 order by email desc;
    特別的:若是對主鍵排序,則仍是速度很快:
        select * from tb1 order by nid desc;
 
- 組合索引最左前綴
    若是組合索引爲:(name,email)
    name and email       -- 命中索引
    name                 -- 命中索引
    email                -- 未命中索引


- count(1)或count(列)代替count(*)在mysql中沒有差異了

- create index xxxx  on tb(title(19)) #text類型,必須制定長度

二 其餘注意事項

- 避免使用select *
- count(1)或count(列) 代替 count(*)
- 建立表時儘可能時 char 代替 varchar
- 表的字段順序固定長度的字段優先
- 組合索引代替多個單列索引(常用多個條件查詢時)
- 儘可能使用短索引
- 使用鏈接(JOIN)來代替子查詢(Sub-Queries)
- 連表時注意條件類型需一致
- 索引散列值(重複少)不適合建索引,例:性別不適合

八 聯合索引與覆蓋索引

一 聯合索引

聯合索引時指對錶上的多個列合起來作一個索引。聯合索引的建立方法與單個索引的建立方法同樣,不一樣之處在僅在於有多個索引列,以下

mysql> create table t(
    -> a int,
    -> b int,
    -> primary key(a),
    -> key idx_a_b(a,b)
    -> );
Query OK, 0 rows affected (0.11 sec)

 那麼什麼時候須要使用聯合索引呢?在討論這個問題以前,先來看一下聯合索引內部的結果。從本質上來講,聯合索引就是一棵B+樹,不一樣的是聯合索引的鍵值得數量不是1,而是>=2。接着來討論兩個整型列組成的聯合索引,假定兩個鍵值得名稱分別爲a、b如圖

 

能夠看到這與咱們以前看到的單個鍵的B+樹並無什麼不一樣,鍵值都是排序的,經過葉子結點能夠邏輯上順序地讀出全部數據,就上面的例子來講,即(1,1),(1,2),(2,1),(2,4),(3,1),(3,2),數據按(a,b)的順序進行了存放。

所以,對於查詢select * from table where a=xxx and b=xxx, 顯然是能夠使用(a,b) 這個聯合索引的,對於單個列a的查詢select * from table where a=xxx,也是能夠使用(a,b)這個索引的。

但對於b列的查詢select * from table where b=xxx,則不能夠使用(a,b) 索引,其實你不難發現緣由,葉子節點上b的值爲一、二、一、四、一、2顯然不是排序的,所以對於b列的查詢使用不到(a,b) 索引

聯合索引的第二個好處是在第一個鍵相同的狀況下,已經對第二個鍵進行了排序處理,例如在不少狀況下應用程序都須要查詢某個用戶的購物狀況,並按照時間進行排序,最後取出最近三次的購買記錄,這時使用聯合索引能夠幫咱們避免多一次的排序操做,由於索引自己在葉子節點已經排序了,以下

#===========準備表==============
create table buy_log(
    userid int unsigned not null,
    buy_date date
);

insert into buy_log values
(1,'2009-01-01'),
(2,'2009-01-01'),
(3,'2009-01-01'),
(1,'2009-02-01'),
(3,'2009-02-01'),
(1,'2009-03-01'),
(1,'2009-04-01');

alter table buy_log add key(userid);
alter table buy_log add key(userid,buy_date);

#===========驗證==============
mysql> show create table buy_log;
| buy_log | CREATE TABLE `buy_log` (
  `userid` int(10) unsigned NOT NULL,
  `buy_date` date DEFAULT NULL,
  KEY `userid` (`userid`),
  KEY `userid_2` (`userid`,`buy_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

#能夠看到possible_keys在這裏有兩個索引能夠用,分別是單個索引userid與聯合索引userid_2,可是優化器最終選擇了使用的key是userid由於該索引的葉子節點包含單個鍵值,因此理論上一個頁能存放的記錄應該更多
mysql> explain select * from buy_log where userid=2;
+----+-------------+---------+------+-----------------+--------+---------+-------+------+-------+
| id | select_type | table   | type | possible_keys   | key    | key_len | ref   | rows | Extra |
+----+-------------+---------+------+-----------------+--------+---------+-------+------+-------+
|  1 | SIMPLE      | buy_log | ref  | userid,userid_2 | userid | 4       | const |    1 |       |
+----+-------------+---------+------+-----------------+--------+---------+-------+------+-------+
1 row in set (0.00 sec)

#接着假定要取出userid爲1的最近3次的購買記錄,用的就是聯合索引userid_2了,由於在這個索引中,在userid=1的狀況下,buy_date都已經排序好了
mysql> explain select * from buy_log where userid=1 order by buy_date desc limit 3;
+----+-------------+---------+------+-----------------+----------+---------+-------+------+--------------------------+
| id | select_type | table   | type | possible_keys   | key      | key_len | ref   | rows | Extra                    |
+----+-------------+---------+------+-----------------+----------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | buy_log | ref  | userid,userid_2 | userid_2 | 4       | const |    4 | Using where; Using index |
+----+-------------+---------+------+-----------------+----------+---------+-------+------+--------------------------+
1 row in set (0.00 sec)

#ps:若是extra的排序顯示是Using filesort,則意味着在查出數據後須要二次排序


#對於聯合索引(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;

二 覆蓋索引

InnoDB存儲引擎支持覆蓋索引(covering index,或稱索引覆蓋),即從輔助索引中就能夠獲得查詢記錄,而不須要查詢彙集索引中的記錄。

使用覆蓋索引的一個好處是:輔助索引不包含整行記錄的全部信息,故其大小要遠小於彙集索引,所以能夠減小大量的IO操做


 注意:覆蓋索引技術最先是在InnoDB Plugin中完成並實現,這意味着對於InnoDB版本小於1.0的,或者MySQL數據庫版本爲5.0如下的,InnoDB存儲引擎不支持覆蓋索引特性


對於InnoDB存儲引擎的輔助索引而言,因爲其包含了主鍵信息,所以其葉子節點存放的數據爲(primary key1,priamey key2,...,key1,key2,...)。例如

select age from s1 where id=123 and name = 'egon'; #id字段有索引,可是name字段沒有索引,該sql命中了索引,但未覆蓋,須要去彙集索引中再查找詳細信息。
最牛逼的狀況是,索引字段覆蓋了全部,那全程經過索引來加速查詢以及獲取結果就ok了
mysql> desc s1;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| name | varchar(20) | YES | | NULL | |
| gender | char(6) | YES | | NULL | |
| email | varchar(50) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.21 sec)

mysql> explain select name from s1 where id=1000; #沒有任何索引
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 2688336 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> create index idx_id on s1(id); #建立索引
Query OK, 0 rows affected (4.16 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> explain select name from s1 where id=1000; #命中輔助索引,可是未覆蓋索引,還須要從彙集索引中查找name
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| 1 | SIMPLE | s1 | NULL | ref | idx_id | idx_id | 4 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.08 sec)

mysql> explain select id from s1 where id=1000; #在輔助索引中就找到了所有信息,Using index表明覆蓋索引
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | s1 | NULL | ref | idx_id | idx_id | 4 | const | 1 | 100.00 | Using index |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.03 sec)

覆蓋索引的另一個好處是對某些統計問題而言的。基於上一小結建立的表buy_log,查詢計劃以下

mysql> explain select count(*) from buy_log;
+----+-------------+---------+-------+---------------+--------+---------+------+------+-------------+
| id | select_type | table   | type  | possible_keys | key    | key_len | ref  | rows | Extra       |
+----+-------------+---------+-------+---------------+--------+---------+------+------+-------------+
|  1 | SIMPLE      | buy_log | index | NULL          | userid | 4       | NULL |    7 | Using index |
+----+-------------+---------+-------+---------------+--------+---------+------+------+-------------+
1 row in set (0.00 sec)

innodb存儲引擎並不會選擇經過查詢彙集索引來進行統計。因爲buy_log表有輔助索引,而輔助索引遠小於彙集索引,選擇輔助索引能夠減小IO操做,故優化器的選擇如上key爲userid輔助索引

對於(a,b)形式的聯合索引,通常是不能夠選擇b中所謂的查詢條件。但若是是統計操做,而且是覆蓋索引,則優化器仍是會選擇使用該索引,以下

#聯合索引userid_2(userid,buy_date),通常狀況,咱們按照buy_date是沒法使用該索引的,但特殊狀況下:查詢語句是統計操做,且是覆蓋索引,則按照buy_date當作查詢條件時,也能夠使用該聯合索引
mysql> explain select count(*) from buy_log where buy_date >= '2011-01-01' and buy_date < '2011-02-01';
+----+-------------+---------+-------+---------------+----------+---------+------+------+--------------------------+
| id | select_type | table   | type  | possible_keys | key      | key_len | ref  | rows | Extra                    |
+----+-------------+---------+-------+---------------+----------+---------+------+------+--------------------------+
|  1 | SIMPLE      | buy_log | index | NULL          | userid_2 | 8       | NULL |    7 | Using where; Using index |
+----+-------------+---------+-------+---------------+----------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

九 查詢優化神器-explain

關於explain命令相信你們並不陌生,具體用法和字段含義能夠參考官網explain-output,這裏須要強調rows是核心指標,絕大部分rows小的語句執行必定很快(有例外,下面會講到)。因此優化語句基本上都是在優化rows。

執行計劃:讓mysql預估執行操做(通常正確)
    all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
    id,email
    
    慢:
        select * from userinfo3 where name='alex'
        
        explain select * from userinfo3 where name='alex'
        type: ALL(全表掃描)
            select * from userinfo3 limit 1;
    快:
        select * from userinfo3 where email='alex'
        type: const(走索引)

http://blog.itpub.net/29773961/viewspace-1767044/

十 慢查詢優化的基本步驟

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

十一 慢日誌管理

 慢日誌
            - 執行時間 > 10
            - 未命中索引
            - 日誌文件路徑
            
        配置:
            - 內存
                show variables like '%query%';
                show variables like '%queries%';
                set global 變量名 = 值
            - 配置文件
                mysqld --defaults-file='E:\wupeiqi\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini'
                
                my.conf內容:
                    slow_query_log = ON
                    slow_query_log_file = D:/....
                    
                注意:修改配置文件以後,須要重啓服務

日誌管理:

MySQL日誌管理
========================================================
錯誤日誌: 記錄 MySQL 服務器啓動、關閉及運行錯誤等信息
二進制日誌: 又稱binlog日誌,以二進制文件的方式記錄數據庫中除 SELECT 之外的操做
查詢日誌: 記錄查詢的信息
慢查詢日誌: 記錄執行時間超過指定時間的操做
中繼日誌: 備庫將主庫的二進制日誌複製到本身的中繼日誌中,從而在本地進行重放
通用日誌: 審計哪一個帳號、在哪一個時段、作了哪些事件
事務日誌或稱redo日誌: 記錄Innodb事務相關的如事務執行時間、檢查點等
========================================================
1、bin-log
1. 啓用
# vim /etc/my.cnf
[mysqld]
log-bin[=dir\[filename]]
# service mysqld restart
2. 暫停
//僅當前會話
SET SQL_LOG_BIN=0;
SET SQL_LOG_BIN=1;
3. 查看
查看所有:
# mysqlbinlog mysql.000002
按時間:
# mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56"
# mysqlbinlog mysql.000002 --stop-datetime="2012-12-05 11:02:54"
# mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56" --stop-datetime="2012-12-05 11:02:54" 

按字節數:
# mysqlbinlog mysql.000002 --start-position=260
# mysqlbinlog mysql.000002 --stop-position=260
# mysqlbinlog mysql.000002 --start-position=260 --stop-position=930
4. 截斷bin-log(產生新的bin-log文件)
a. 重啓mysql服務器
b. # mysql -uroot -p123 -e 'flush logs'
5. 刪除bin-log文件
# mysql -uroot -p123 -e 'reset master' 


2、查詢日誌
啓用通用查詢日誌
# vim /etc/my.cnf
[mysqld]
log[=dir\[filename]]
# service mysqld restart

3、慢查詢日誌
啓用慢查詢日誌
# vim /etc/my.cnf
[mysqld]
log-slow-queries[=dir\[filename]]
long_query_time=n
# service mysqld restart
MySQL 5.6:
slow-query-log=1
slow-query-log-file=slow.log
long_query_time=3
查看慢查詢日誌
測試:BENCHMARK(count,expr)
SELECT BENCHMARK(50000000,2*3);
相關文章
相關標籤/搜索