1. 程式人生 > >數據庫優化(二)—— MySQL索引優化

數據庫優化(二)—— MySQL索引優化

大表加索引 運算 維護 重構 unit num .sh 規範 -s

目錄

  • MySQL的索引優化
    • 一、MySQL 5.7的初始化配置
    • 二、MySQL配置文件
      • 1、配置
      • 2、配置文件作用
    • 三、多實例
      • 1、創建相關的目錄
      • 2、創建實例的配置文件
      • 3、初始化
      • 4、授權
      • 5、啟動實例
      • 6、查看啟動狀況
      • 7、測試
      • 8、配置啟動腳本
      • 9、開機自啟
      • 10、設定mysql密碼
      • 11、忘記密碼
    • 四、數據類型
      • 1、整型
      • 2、字符串類型
      • 3、時間類型
      • 規範
    • 五、索引
      • 1、索引作用
      • 2、索引種類
      • 3、Btree 分類
      • 4、聚集索引和輔助索引的對比
    • 六、MySQL索引管理
      • 1、創建索引(輔助索引)
      • 2、刪除索引
      • 3、查看創建的索引
      • 4、前綴索引
      • 5、唯一鍵索引
      • 6、覆蓋索引(聯合索引)
    • 七、explain(desc)命令的應用
      • 1、字段
      • (2)Extra
      • (3)其他字段
    • 八、建立索引規範
    • 九、建立索引原則
    • 十、不走索引的情況
    • 十一、壓力測試

MySQL的索引優化

一、MySQL 5.7的初始化配置

/usr/local/mysql/bin/mysqld --initialize-insecure  --user=mysql --datadir=/opt/mysql/data --basedir=/opt/mysql

二、MySQL配置文件

1、配置

vim /etc/my.cnf
    [mysqld]
    basedir = /opt/mysql
    datadir = /opt/mysql/data
    port = 3306
    user = mysql
    socket = /tmp/mysql.sock
    log_error = /var/log/mysql.log
    [mysql]
    socket=/tmp/mysql.sock

2、配置文件作用

(1)影響服務端的啟動

標簽:[mysqld]   [mysqld_safe]   [server]   ...
  • 必須配置的內容
[mysqld]
basedir = /opt/mysql
datadir = /opt/mysql/data
user = mysql
socket = /tmp/mysql.sock
port = 3306
server_id = 6

(2)影響客戶端的連接

標簽:[client]  [mysql]    [mysqldump] ...
  • 配置內容
[mysql]
socket = /tmp/mysql.sock

(3)影響初始化

三、多實例

端口號為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/*

5、啟動實例

mysqld_safe --defaults-file=/data/3307/my.cnf &
mysqld_safe --defaults-file=/data/3308/my.cnf &
mysqld_safe --defaults-file=/data/3309/my.cnf &

6、查看啟動狀況

netstat -lnp|grep 330

7、測試

mysql -S /data/3307/mysql.sock
mysql -S /data/3308/mysql.sock
mysql -S /data/3309/mysql.sock

8、配置啟動腳本

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

    
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

9、開機自啟

[root@standby ~]# systemctl start mysqld3307
[root@standby ~]# systemctl start mysqld3308
[root@standby ~]# systemctl start mysqld3309
[root@standby ~]# netstat -lnp|grep 330
tcp6       0      0 :::3307                 :::*                    LISTEN      3773/mysqld         
tcp6       0      0 :::3308                 :::*                    LISTEN      3808/mysqld         
tcp6       0      0 :::3309                 :::*                    LISTEN      3843/mysqld         
tcp6       0      0 :::3306                 :::*                    LISTEN      2721/mysqld         
[root@standby ~]# systemctl stop mysqld3309
[root@standby ~]# systemctl stop mysqld3308
[root@standby ~]# systemctl stop mysqld3307

[root@standby ~]# systemctl enable  mysqld3307
[root@standby ~]# systemctl enable  mysqld3308
[root@standby ~]# systemctl enable  mysqld3309

10、設定mysql密碼

mysqladmin -uroot -p password 123

11、忘記密碼

# root等用戶信息存在mysql.user表中
select user,authentication_string,host from mysql.user;

# 1.停數據庫
/etc/init.d/mysqld stop
# 2.啟動數據庫為無密碼驗證模式
mysqld_safe --skip-grant-tables --skip-networking  &
update mysql.user set authentication_string=PASSWORD(‘456‘) where user=‘root‘ and host=‘localhost‘;
/etc/init.d/mysqld restart

[root@standby ~]# mysql -uroot -p123
[root@standby ~]# mysql -uroot -p456

四、數據類型

1、整型

int 
最多存10位數字:-2^31 ~ 2^31-1

2、字符串類型

char       定長,存儲效率高,但是對於變化多的字段,空間浪費高
varchar    變長,存儲時判斷長度,存儲會有額外開銷,按需分配空間
enum       枚舉類型

3、時間類型

datetime    日期+時間
date        日期
timestamp   時間戳
time      時間

規範

  • 少於10位數,用 int;大於10位用 char
  • char 和 varchar 選擇時,字符長度一定不變用 char ;字符長度改變的用 varchar
    在使用可變的數據類型時,將來使用不同的數據類型,對於索引樹的高度會有影響
  • 選擇合適的數據類型
  • 合適長度

五、索引

1、索引作用

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

2、索引種類

  • Btree(btree b+tree b*tree)

  • Rtree
  • HASH
  • FullText

3、Btree 分類

聚集索引:基於主鍵,自動生成的,一般是建表時創建主鍵。如果沒有主鍵,自動選擇唯一鍵做為聚集索引
輔助索引:人為創建的(普通,覆蓋)
唯一索引:人為創建(普通索引,聚集索引)

4、聚集索引和輔助索引的對比

  • 聚集索引:葉子結點,按照主鍵列的順序,存儲的整行數據,就是真正的數據頁
  • 輔助索引: 葉子結點,列值排序之後,存儲到葉子結點+對應的主鍵的值,便於回表查詢

六、MySQL索引管理

1、創建索引(輔助索引)

alter table blog_blog add key idx_name(name);
# 或者
create index index_name on blog_blog(name);

2、刪除索引

alter table blog_blog drop key idx_name(name);
# 或者
drop index index_name on blog_blog(name);

3、查看創建的索引

show index from blog_blog;

4、前綴索引

# select count(*),substring(password,1,20) as sbp  from blog_userinfo group by sbp;
alter table blog_userinfo add index idx(password(10));

5、唯一鍵索引

alter table blog_blog add unique key uni_name(name);

6、覆蓋索引(聯合索引)

作用:不需要回表查詢,不需要聚集索引,所有的數據都從輔助索引中獲取

alter table t1 add index idx_abc(age,box,electric);   # 第一個為主要條件,第一條件,查詢量多的條件放前面,有序

# 查詢的時候,where後面條件不是age放首位的條件,都不走聯合索引

七、explain(desc)命令的應用

獲取優化器選擇後的執行計劃

 oldguo [world]>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
1 row in set (0.00 sec)

1、字段

(1)type —— 查詢類型(上至下性能增加)

  • 判斷是全表掃描還是索引掃描(ALL是全表掃描,其他的是索引掃描)

  • 判斷是哪一種類的索引掃描
    ALL:全表掃描 —— select * from t1;
    Index:全索引掃描 —— desc select countrycode from city ;

    range:索引範圍掃描 —— where > < >= <= in or between and like ‘CH‘

    select * from city where country in (‘China‘,‘USA‘)s

    ref:輔助索引等值查詢 —— in與or替換為union的查詢效率會提高

    select * from city where country=‘China‘
    union all
    select * from city where country=‘USA‘

    eq_ref:多表連接查詢(join on )

    constsystem :主鍵或唯一鍵等值查詢

(2)Extra

using filesort:文件排序,可以進行優化

將order by、group by、distinct 後面的列和where條件列建立聯合索引

(3)其他字段

possible_keys: CountryCode,idx_co_po      ---->可能會走的索引
key: CountryCode                          ---->真正走的索引
type: ref                                 ---->索引類型
Extra: Using index condition              ---->額外信息

八、建立索引規範

1、建表時一定要有主鍵,如果相關列可以作為主鍵,做一個無關列

2、選擇唯一性索引

唯一性索引的值是唯一的,可以更快速的通過該索引來確定某條記錄。

主鍵索引和唯一鍵索引,在查詢中使用是效率最高的。

註意:如果重復值較多,可以考慮采用聯合索引

3、為經常需要排序、分組和聯合操作的字段建立索引

經常需要ORDER BY、GROUP BY,join on等操作的字段,排序操作會浪費很多時間。
如果為其建立索引,可以有效地避免排序操作。

4、為常作為where查詢條件的字段建立索引

如果某個字段經常用來做查詢條件,那麽該字段的查詢速度會影響整個表的查詢速度。因此,
為這樣的字段建立索引,可以提高整個表的查詢速度。

5、盡量使用前綴來索引
如果索引字段的值很長,最好使用值的前綴來索引。例如,TEXT和BLOG類型的字段,進行全文檢索
會很浪費時間。如果只檢索字段的前面的若幹個字符,這樣可以提高檢索速度。

6.限制索引的數目
索引的數目不是越多越好。每個索引都需要占用磁盤空間,索引越多,需要的磁盤空間就越大。
修改表時,對索引的重構和更新很麻煩。越多的索引,會使更新表變得很浪費時間。

7.刪除不再使用或者很少使用的索引(percona toolkit)
表中的數據被大量更新,或者數據的使用方式被改變後,原有的一些索引可能不再需要。數據庫管理
員應當定期找出這些索引,將它們刪除,從而減少索引對更新操作的影響。

8.大表加索引,要在業務不繁忙期間操作


九、建立索引原則

(1) 必須要有主鍵,如果沒有可以做為主鍵條件的列,創建無關列

(2) 經常做為where條件列 order by group by join on的條件(業務:產品功能+用戶行為)

(3) 最好使用唯一值多的列作為索引,如果索引列重復值較多,可以考慮使用聯合索引

(4) 列值長度較長的索引列,我們建議使用前綴索引.

(5) 降低索引條目,一方面不要創建沒用索引,不常使用的索引清理,percona toolkit

(6) 索引維護要避開業務繁忙期

十、不走索引的情況

1、沒有查詢條件,或者查詢條件沒有建立索引

2、查詢結果集是原表中的大部分數據,應該是25%以上

3、索引本身失效,統計數據不真實

4、查詢條件使用函數在索引列上,或者對索引列進行運算,運算包括(+,-,*,/,! 等)

5、隱式轉換導致索引失效.這一點應當引起重視,也是開發中經常會犯的錯誤.

6、<> ,not in 不走索引

7、 like "%_" 百分號在最前面不走

8、單獨引用聯合索引裏非第一位置的索引列.作為條件查詢時不走索引.

十一、壓力測試

1、模擬數據庫數據

vim slap.sh
    ...
    
# 執行腳本:
sh slap.sh

2、檢查數據可用性

mysql -uroot -p123
select count(*) from oldboy.t1;

3、優化前進行壓力測試

mysqlslap --defaults-file=/etc/my.cnf  --concurrency=100 --iterations=1 --create-schema=‘oldboy‘ --query="select * from oldboy.t1 where stuname=‘alexsb_100‘" engine=innodb --number-of-queries=2000 -uroot -p123 -verbose

4、創建索引再測試

mysql> alter table t1 add index idx_name(stuname);

# 重復第三步,進行壓力測試

數據庫優化(二)—— MySQL索引優化