MySQL深刻學習(二)--配置、索引、執行計劃

MySQL

1、MySQL 5.7 初始化配置

1.初始化數據並配置

# 1.初始化數據
/usr/local/mysql/bin/mysqld --initialize-insecure  --user=mysql --datadir=/opt/mysql/data --basedir=/opt/mysql

# 2.配置文件
vim /etc/my.cnf
[mysqld]
basedir=/usr/local/mysql
datadir=/usr/local/mysql/mydata
socket=/tmp/mysql.sock
log_error=/var/log/mysql.log
user=mysql
port=6606
[mysql]
socket=/tmp/mysql.sock


# 做用:
# 1.影響服務端的啓動
# 標籤: [mysqld]   [mysqld_safe]  [server] ...
[mysqld]
basedir=/opt/mysql          # 指定Mysql安裝的絕對路徑  
datadir=/opt/mysql/data     # Mysql數據存放的絕對路徑
user=mysql                  # 默認使用mysql來啓動mysqld程序。
socket=/tmp/mysql.sock      # 套接字文件
port=3306                   # 指定了Mysql開放的端口
server_id=6

# 2.影響客戶端鏈接
# 標籤: [client]   [mysql]  [mysqldump] ....
[mysql] 
socket=/tmp/mysql.sock      # 套接字文件

2.多實例(3307 3308 3309)

# 1.建立相關目錄
mkdir -p /data/330{7..9}/data 

# 2.建立配置文件
cat>> /data/3307/my.cnf<<EOF
[mysqld]
basedir=/opt/mysql              
datadir=/data/3307/data
user=mysql
socket=/data/3307/mysql.sock
port=3307 
server_id=3307
EOF

cp /data/3307/my.cnf /data/3308 
cp /data/3307/my.cnf /data/3309 

sed -i 's#3307#3308#g' /data/3308/my.cnf 
sed -i 's#3307#3309#g' /data/3309/my.cnf 


# 3.初始化數據 
mysqld --initialize-insecure  --user=mysql --datadir=/data/3307/data --basedir=/opt/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/3308/data --basedir=/opt/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/3309/data --basedir=/opt/mysql


# 4.啓動多實例
chown -R mysql.mysql /data/*
mysqld_safe --defaults-file=/data/3307/my.cnf &
mysqld_safe --defaults-file=/data/3308/my.cnf &
mysqld_safe --defaults-file=/data/3309/my.cnf &

 
# 5.測試 
# 查看端口
netstat -lnp|grep 330
# 測試是否可使用
mysql -S /data/3307/mysql.sock
mysql -S /data/3308/mysql.sock
mysql -S /data/3309/mysql.sock

# 6.systemd管理多實例
# 配置
cat >> /etc/systemd/system/mysqld3307.service <<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/opt/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf
LimitNOFILE = 5000
EOF

# 把配置好的3307的配置文件,複製給330八、3309
cp  /etc/systemd/system/mysqld3307.service   /etc/systemd/system/mysqld3308.service 
cp  /etc/systemd/system/mysqld3307.service   

/etc/systemd/system/mysqld3309.service 
sed -i 's#3307#3308#g'   /etc/systemd/system/mysqld3308.service
sed -i 's#3307#3309#g'   /etc/systemd/system/mysqld3309.service


# 之後能夠用 systemctl 來啓動
systemctl start mysqld3307
systemctl start mysqld3308
systemctl start mysqld3309

# 設置開機啓動
systemctl enable  mysqld3307
systemctl enable  mysqld3308
systemctl enable  mysqld3309

2、MySQL密碼

# 設置root用戶密碼123
mysqladmin -uroot -p password 123

# 能夠去用戶表裏查看用戶名,密碼,HOST
select user,authentication_string,host from mysql.user;



# 忘記密碼
# 1.中止數據庫
/etc/init.d/mysqld stop

# 2.啓動數據庫爲無密碼驗證模式
mysqld_safe --skip-grant-tables --skip-networking  &

# 3.修改密碼
update mysql.user set authentication_string=PASSWORD('456') where user='root' and host='localhost';

# 4.重啓MySQL服務
/etc/init.d/mysqld restart


# 5.測試
mysql -uroot -p123
mysql -uroot -p456

3、數據類型和字符集

整型
    int 最多存10位數字
        -2^31 ~ 2^31-1
          2^32  10位數    11 
    浮點
    
    字符串類型
        char      定長,存儲數據效率較高,對於變化較多的字段,空間浪費較多
        varchar   變長,存儲時判斷長度,存儲會有額外開銷,按需分配存儲空間.
        enum
    時間
        datetime  
        timestamp
        date
        time    

# SQL語句規範第五條:   
    1.少於10位的數字int ,大於10位數 char,例如手機號
    2.char和varchar選擇時,字符長度必定不變的可使用char,可變的儘可能使用varchar
      在可變長度的存儲時,未來使用不一樣的數據類型,對於索引樹的高度是有影響的.
    3.選擇合適的數據類型
    4.合適長度

4、索引

1.索引

索引就是表中的某個列python

做用: 優化查詢mysql

select 查詢有三種狀況:緩存查詢(不在mysql中進行數據查詢),全表掃描,索引掃描sql

2.索引分類

  • Btree(btree b+tree b*tree)數據庫

    即二叉搜索樹:vim

    ​ 1.全部非葉子結點至多擁有兩個兒子(Left和Right);緩存

    ​ 2.全部結點存儲一個關鍵字;mysql優化

    ​ 3.非葉子結點的左指針指向小於其關鍵字的子樹,右指針指向大於其關鍵字的子樹;socket

  • Rtree性能

  • HASH

  • FullText

3.btree

B-Tree是爲磁盤等外存儲設備設計的一種平衡查找樹。所以在講B-Tree以前先了解下磁盤的相關知識。

系統從磁盤讀取數據到內存時是以磁盤塊(block)爲基本單位的,位於同一個磁盤塊中的數據會被一次性讀取出來,而不是須要什麼取什麼。

InnoDB存儲引擎中有頁(Page)的概念,頁是其磁盤管理的最小單位。InnoDB存儲引擎中默認每一個頁的大小爲16KB

而系統一個磁盤塊的存儲空間每每沒有這麼大,所以InnoDB每次申請磁盤空間時都會是若干地址連續磁盤塊來達到頁的大小16KB。InnoDB在把磁盤數據讀入到磁盤時會以頁爲基本單位,在查詢數據時若是一個頁中的每條數據都能有助於定位數據記錄的位置,這將會減小磁盤I/O次數,提升查詢效率。

B-Tree結構的數據可讓系統高效的找到數據所在的磁盤塊。爲了描述B-Tree,首先定義一條記錄爲一個二元組[key, data] ,key爲記錄的鍵值,對應表中的主鍵值,data爲一行記錄中除主鍵外的數據。對於不一樣的記錄,key值互不相同。

一棵m階的B-Tree有以下特性: 

  1. 每一個節點最多有m個孩子。 
  2. 除了根節點和葉子節點外,其它每一個節點至少有Ceil(m/2)個孩子。 
  3. 若根節點不是葉子節點,則至少有2個孩子 
  4. 全部葉子節點都在同一層,且不包含其它關鍵字信息 
  5. 每一個非終端節點包含n個關鍵字信息(P0,P1,…Pn, k1,…kn) 
  6. 關鍵字的個數n知足:ceil(m/2)-1 <= n <= m-1 
  7. ki(i=1,…n)爲關鍵字,且關鍵字升序排序。 
  8. Pi(i=1,…n)爲指向子樹根節點的指針。P(i-1)指向的子樹的全部節點關鍵字均小於ki,但都大於k(i-1)

B-Tree中的每一個節點根據實際狀況能夠包含大量的關鍵字信息和分支,以下圖所示爲一個3階的B-Tree:

每一個節點佔用一個盤塊的磁盤空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指針,指針存儲的是子節點所在磁盤塊的地址。兩個關鍵詞劃分紅的三個範圍域對應三個指針指向的子樹的數據的範圍域。以根節點爲例,關鍵字爲17和35,P1指針指向的子樹的數據範圍爲小於17,P2指針指向的子樹的數據範圍爲17~35,P3指針指向的子樹的數據範圍爲大於35。

模擬查找關鍵字29的過程:

  1. 根據根節點找到磁盤塊1,把磁盤塊1讀入內存。【磁盤I/O操做第1次】
  2. 比較關鍵字29在區間(17,35),找到磁盤塊1的指針P2。
  3. 根據P2指針找到磁盤塊3,把磁盤塊3讀入內存。【磁盤I/O操做第2次】
  4. 比較關鍵字29在區間(26,30),找到磁盤塊3的指針P2。
  5. 根據P2指針找到磁盤塊8,把磁盤塊8讀入內存。【磁盤I/O操做第3次】
  6. 在磁盤塊8中的關鍵字列表中找到關鍵字29。

從這看來,每次查找一個數,只須要通過三步便可,大大的提升了查找效率

缺點:

1.每一個節點中不只包含數據的key值,還有data值。而每個頁的存儲空間是有限的,若是data數據較大時將會致使每一個節點(即一個頁)能存儲的key的數量很小,當存儲的數據量很大時一樣會致使B-Tree的深度較大,增大查詢時的磁盤I/O次數,進而影響查詢效率。

2.每次查詢須要從根節點開始查詢,若是執行次數過多,效率同樣不高

4.B+Tree

B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外存儲索引結構,InnoDB存儲引擎就是用B+Tree實現其索引結構。

# B+Tree相對於B-Tree有幾點不一樣:

1. 非葉子節點只存儲鍵值信息。
2. 全部葉子節點之間都有一個鏈指針。
3. 數據記錄都存放在葉子節點中。
# B+Tree的優勢:

1. 因爲相鄰的葉子節點之間有連接,因此查詢相鄰的數據時,不用再次從頭開始執行,執行效率高
2. 由於非葉子節點只存儲鍵值信息,而且數據記錄都存放在葉子節點中,因此大大提升每一個節點存儲的key值數量,下降B+Tree的高度。

將上一節中的B-Tree優化,因爲B+Tree的非葉子節點只存儲鍵值信息,假設每一個磁盤塊能存儲4個鍵值及指針信息,則變成B+Tree後其結構以下圖所示:

5.Btree 分類

數據庫中的B+Tree索引能夠分爲

  • 彙集索引:基於主鍵,自動生成的,通常是建表時建立主鍵.若是沒有主鍵,自動選擇惟一鍵作爲彙集索引.
  • 輔助索引:人爲建立的(普通,覆蓋)
  • 惟一索引:人爲建立(普通索引,彙集索引)
# 彙集索引和輔助索引的對比

1.彙集索引:
    葉子結點按照主鍵列的順序,存儲的整行數據,就是真正的數據頁
    
2.輔助索引: 
    葉子節點並不包含行記錄的所有數據,而是存儲相應行數據的彙集索引鍵,即主鍵。當經過輔助索引來查詢數據時,InnoDB存儲引擎會遍歷輔助索引找到主鍵,而後再經過主鍵在彙集索引中找到完整的行記錄數據,便於回表查詢

6.索引管理命令

# 輔助索引(MUL)
根據建立索引時,指定的列的值,進行排序後,存儲的葉子節點中
# 好處:
1.優化了查詢,減小cpu mem IO消耗
2.減小的文件排序

# 建立普通索引(MUL)
# alter或create
alter table blog_userinfo add key idx_email(email);
create index idx_phone on blog_userinfo(phone);

# 查看索引
# desc或show
desc blog_userinfo;
show index from blog_userinfo;

# 刪除索引
# alter或drop
alter table blog_userinfo drop index idx_email;
drop index idx_phone on   blog_userinfo;

# 前綴索引
# 先查看一下多少前綴
select count(*),substring(password,1,20) as sbp  from blog_userinfo group by sbp;
# 在建立前綴索引
alter table blog_userinfo add index idx(password(10));




# 惟一鍵索引(UNI,若是有重複值是建立不了的)
# 建立
alter table blog_userinfo add unique key uni_email(email);



# 覆蓋索引(聯合索引)
做用:不須要回表查詢,不須要彙集索引,全部查詢的數據都從輔助索引中獲取
好處:減小回表查詢的概率
# 建立 
alter table t1 add index idx_gam(gender,age,money);

# 一旦創建覆蓋索引,再次查詢時,最好按照建立的順序查詢
# 好比以a,b,c爲覆蓋索引
# a,b,c效率最高
select *  from  people   where  a,b,c
# a,c,b效率其次
# c或b第一位效率最低

5、執行計劃

實際項目開發中,因爲咱們不知道實際查詢的時候數據庫裏發生了什麼事情,數據庫軟件是怎樣掃描表、怎樣使用索引的,所以,咱們能感知到的就只有

sql語句運行的時間,在數據規模不大時,查詢是瞬間的,所以,在寫sql語句的時候就不多考慮到性能的問題。可是當數據規模增大,如千萬、億的時候,咱們運

行一樣的sql語句時卻發現遲遲沒有結果,這個時候才知道數據規模已經限制了咱們查詢的速度。因此,查詢優化和索引也就顯得很重要了。

# 經過查詢執行計劃,能夠知道這個語句到底執行了什麼
# explain或desc
explain select * from city where countrycode='CHN'\G


*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: city
         type: ref
possible_keys: CountryCode,idx_co_po
          key: CountryCode
      key_len: 3
          ref: const
         rows: 1
        Extra: Using index condition
            
            
# 是不是複雜語句      
select_type:SIMPLE
    
# 顯示這一行的數據是關於哪張表的
table: city
    
# 顯示鏈接使用了何種類型    
type: ref
    1. 能夠判斷出,全表掃描仍是索引掃描(ALL就是全表掃描,其餘的就是索引掃描)
    2. 對於索引掃描來說,又能夠細劃分,能夠判斷是哪種類的索引掃描
    type的具體類型介紹:
        ALL:全表掃描 
            select  *  from  t1;
        Index:全索引掃描
            select countrycode from city ;
        
        range:索引範圍掃描
            where >、<、>=、<=、in、or、between and、like 'CH%'
        
            # 注:in 或者 or 改寫成 union  
            select * from city where countrycode in('CHN','USA')
            
                select * from city where countrycode='CHN'
                union all 
                select * from city where countrycode='USA';
    
        ref:輔助索引的等值查詢
            select * from city where countrycode='CHN'
    
        eq_ref: 多表連接查詢(join on )
    
        const ,system :主鍵或惟一鍵等值查詢

# 顯示可能應用在這張表中的索引。若是爲空,沒有可能的索引。
possible_keys: CountryCode,idx_co_po

# 實際使用的索引。
key: CountryCode
    
# 使用的索引的長度。在不損失精確性的狀況下,長度越短越好
key_len: 3
    
# 顯示索引的哪一列被使用了,若是可能的話,是一個常數
ref: const
    
# MYSQL認爲必須檢查的用來返回請求數據的行數
rows: 1
    
# 關於MYSQL如何解析查詢的額外信息。
Extra: Using index condition
    Distinct :一旦mysql找到了與行相聯合匹配的行,就再也不搜索了。

    Not exists :mysql優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行,就再也不搜索了。

    Range checked for each Record:沒有找到理想的索引,所以對從前面表中來的每個行組合,mysql檢查使用哪一個索引,並用它來從表中返回行。這是使用索引的最慢的鏈接之一。

    Using filesort :看到這個的時候,查詢就須要優化了。mysql須要進行額外的步驟來發現如何對返回的行排序。它根據鏈接類型以及存儲排序鍵值和匹配條件的所有行的行指針來排序所有行。

    Using index :列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對錶的所有的請求列都是同一個索引的部分的時候。

    Using temporary :看到這個的時候,查詢須要優化了。這裏,mysql須要建立一個臨時表來存儲結果,這一般發生在對不一樣的列集進行ORDER BY上,而不是GROUP BY上。

    Where used :使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。若是不想返回表中的所有行,而且鏈接類型ALL或index,這就會發生,或者是查詢有問題。
相關文章
相關標籤/搜索