1. 程式人生 > 其它 >mysql sql優化 & 事務處理特徵 & 約束新增、刪除

mysql sql優化 & 事務處理特徵 & 約束新增、刪除

索引樹高度

  1. 表的資料量

    • 資料量越大,樹的高度就會變高,理論上三層索引樹的高度最為理想,可以支援百萬級別的資料量

    • 解決:可以使用分表(橫切,豎切),分庫,增加快取,解決資料量大,查詢慢

  2. 索引鍵值過長

    • 該索引欄位儲存資料太大,滅個葉子節點最大儲存16k,超過這個範圍會新增加葉子節點和分頁節點
    • 解決:字首索引(擷取前5個長度)
  3. 資料型別

    • char(定長) varchar(變長) 從開闢空間的速度來看,char快;從資料結構上看,varchar更為合理
      • (1) 避免使用select ,不確定表大小的時候,使用count()查一下資料
      • (2) 儘量使用資料型別較小的欄位做索引
      • (3) 重複值少的,區分度高的欄位做索引,性別這樣的欄位不要做索引
      • (4) 在奪標查詢時 使用join,儘量少的使用子查詢

執行計劃

  • desc/explain

  • 執行計劃:在一條sql執行之前,指定執行的方案

    desc select * from s1;
    
    mysql> desc select * from ceshi_table;
    +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+
    | id | select_type | table       | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
    +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+
    |  1 | SIMPLE      | ceshi_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |   100.00 | NULL  |
    +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+
    1 row in set, 1 warning (0.00 sec)
    
    
    
    mysql> explain select * from ceshi_table;
    +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+
    | id | select_type | table       | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
    +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+
    |  1 | SIMPLE      | ceshi_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |   100.00 | NULL  |
    +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+
    1 row in set, 1 warning (0.00 sec)
    
    1. select_type

      • simple 代表的是簡單查詢(單邊查詢,不包括子查詢,union)
      • primary sql巢狀中的主查詢(最外層)
      • subquery sql巢狀中的子查詢(最裡面)
      • derived 衍生查詢(把子查詢結果作為一張臨時表)
    2. table

      • 在多表或者子查詢時候,通過table分析出問題的表是誰
    3. type

      • 顯示執行計劃的型別,優先順序從低到高如下,優化時至少達到range或者ref級別

        all < index < range < ref < eq_ref < const < system

      • all 全表掃描(不走索引)

        • 在大範圍內查詢 > < >= <= != between and in like ..
        • where條件中有計算,有函式
        • 資料型別不匹配
        • 拼接條件使用or
      • index 全索引掃描

        • 掃描整個索引樹,才能獲取到所有資料,這樣的索引失去意義

          desc select count(*) from s1;
          
      • range 索引範圍掃描(注意點:範圍太大,不能命中索引),慢查詢

        desc select * from s1 where id < 10;   #type=range
        desc select * from s1 where id < 1000000; #type=all
        desc select * from s1 where id between 1 and 10;#type=range
        desc select * from s1 where id between 1 and 100000; #type=all
        desc select * from s1 where email like "%w%";   #type=all
        desc select * from s1 where email like "w%"; #type=range
        '''如果範圍過大,不能命中索引,如果範圍適當,可以命中索引'''
        desc select * from s1 where id in (1,2,3)
        #對in或者or這樣的語句進行優化
        '''優化:union all比union速度快,union在合併資料之後,多一步去重操作'''
        desc select * from s1 where id=1
        union all
        select * from s1 where id = 1;
        
        desc select * from s1 where id=1
        union 
        select * from s1 where id = 1;
        
        #優化or條件
        desc select * from s1 where id = 10 or name ='aaaa';
        
        desc select * from s1 where id = 10
        union all
        select * from s1 where name = 'aaaa';
        
      • ref 普通索引查詢(非唯一)

        desc select * from s1 where email = 'xboyww10@oldboy';
        desc select * from s1 where id = 10;
        
      • eq_ref 唯一性索引(聯表)

        alter table s1 drop index index_id;
        alter table s1 add primary key(id);
        desc select * from s1 where id = 10;
        
        create database db0624;
        use db0624;
        #建立一張表
        create table class1(id int,classname varchar(255));
        create table student1(
        id int primary key auto_increment,
        name varchar(255) not null,
        age int not null,
        class_id int
        );
        #插入資料
        insert into student1 values(null,;"wangbaoqiang",82,2);
        insert into student1 values(null,;"wanglihong",7,1);
        insert into student1 values(null,;"wangwen",7,2);
        
        insert into class1 values(1,"python30");
        insert into class1 values(2,"python31");
        
        '''要求:應用在多聯表中,被關聯的欄位需要主鍵或者唯一,表之間的關係為一對一併且資料條數相同'''
        desc select student1.age from student1,class1 where student1.class_id = class1.id;#ALL
        alter table class1 add primary key(id);
        
        desc select student1.age from student1,class1 where student1.class_id = class1.id;#INDEX
        delete from student1 where id = 3;
        desc select student1.age from student1,class1 where student1.class_id = class1.id;#EQ_REF
        
      • const:主鍵或者唯一索引(單表)

        '''針對於primary key 和unique索引等值查詢'''
        desc select * from class1 where id=1;  #const
        desc select * from class1 where id>1;  #range
        
      • system(瞭解)

        • 只有一條資料的系統表
    4. possible_keys:執行sql時,可能用到的索引是誰

    5. key:執行sql時,實際用到的索引是誰

      show index from s1;展現表s1所有的索引
      
    6. key_len :判斷聯合索引覆蓋的長度(通過位元組數可以判定出到底觸發了那些)

      #在沒有not null約束的時候,預設預留一個位元組,標記是空或者非空
      #utf8 通常情況下,中文1個字元佔用3個位元組,字母佔用1個位元組,極個別的生僻字佔4個位元組
      #varchar每次儲存資料的時候,系統底層預設會額外預留2個位元組
      		有not null(不為空)	沒有not null(可為空)
      tinyint		1					1+1
      int			4					4+1
      char(5)		5*3					5*3+1
      varchar(5)	5*3 + 2				5*3+2+1
      
      create table t100(
      n1 int,
      n2 int not null,
      n3 char(5),
      n4 char(5) not null,
      n5 varchar(5),
      n6 varchar(5) not null,
      index index_n1(n1,n2,n3),
      index index_n4(n4,n5,n6)
      );
      insert into t100 values(1,2,"a","b","aa","bb");
      insert into t100 values(1,2,"a","b","aa","bb");
      insert into t100 values(1,2,"a","b","aa","bb");
      insert into t100 values(1,2,"a","b","cc","dd");
      
      #把資料表中的資料匯入
      mysql> desc t100;
      +-------+------------+------+-----+---------+-------+
      | Field | Type       | Null | Key | Default | Extra |
      +-------+------------+------+-----+---------+-------+
      | n1    | int(11)    | YES  | MUL | NULL    |       |
      | n2    | int(11)    | NO   |     | NULL    |       |
      | n3    | char(5)    | YES  |     | NULL    |       |
      | n4    | char(5)    | NO   | MUL | NULL    |       |
      | n5    | varchar(5) | YES  |     | NULL    |       |
      | n6    | varchar(5) | NO   |     | NULL    |       |
      +-------+------------+------+-----+---------+-------+
      6 rows in set (0.00 sec)
      mysql> select * from t100;
      +------+----+------+----+------+----+
      | n1   | n2 | n3   | n4 | n5   | n6 |
      +------+----+------+----+------+----+
      |    1 |  2 | a    | b  | aa   | bb |
      |    1 |  2 | a    | b  | aa   | bb |
      |    1 |  2 | a    | b  | aa   | bb |
      |    1 |  2 | a    | b  | cc   | dd |
      +------+----+------+----+------+----+
      4 rows in set (0.00 sec)
      
      n1->5B  n2->4B n3->16B  5+4+16=25
      
      desc select * from t100 where n1 = 2 and n2 = 2 and n3 ="a";#命中n1  n2  n3
      desc select * from t100 where n1 = 1 and n2 = 2 and n3 ="a";#如果有重複資料,不會觸發聯合索引
      desc select * from t100 where n1 = 1 and n2 = 2;#如果有重複資料,不會觸發聯合索引
      desc select * from t100 where n1 = 2 and n2 = 2;# n1 -> 5B  n2->4B 命中n1,n2
      desc select * from t100 where n1 = 2;#n1->5B 命中n1
      desc select * from t100 where n1 = 2 and n3 = "a"; #n1-5B 命中n1,沒有命中n3
      
      #index(a,b,c)-> a,ab,abc 建立了三組索引,符合最字首原則,第一個欄位必須存在才能觸發
      
      

事務處理的四項特徵 ACID

  • A:原子性

    • 同一個事務中執行多條sql語句,要麼全部成功,要麼直接回滾,作為一個完整的整體,不能再繼續分隔的最小個體
  • C:一致性

    • a,i,d 都是為了保證資料的一致性才提出來的,比如約束,鍵在插入資料時,必須按照要求插入,保證規則上的一致性;
    • 上升到事務中,如果出現意外導致資料不一致,例如髒讀,幻讀,不可重讀,最終要保證資料是一致的
    • 上升到主從資料庫,主資料庫增刪改,從資料也要進行同步改變,保證資料的一致性
  • I:隔離性

    • lock + isolation鎖,來處理事務的隔離級別
    • 一個事務和另外一個事務工作過程中彼此獨立隔離
  • D:永續性

    • 把資料寫到磁碟上,保證資料持久化儲存不丟失
  • 隔離性:隔離級別

    + 髒讀:沒提交的資料被讀出來了
    + 不可重讀:前後多次讀書,結果資料內容不一樣(同一個會話裡,在不修改的情況下,永遠只看到同樣的一份資料)
    + 幻讀:前後多次讀取,結果資料的總量不一樣
    
    • RU(READ-UNCOMMITTED):讀未提交:髒讀,不可重讀,幻讀
    • RC (READ-COMMITTED):讀已提交:防止髒讀,會出現不可重讀和幻讀
    • RR(REPEATABLE-READ):可重複讀:防止髒讀,不可重讀,可能會出現幻讀
    • SR (SERIALIZABLE):可序列化:防止一切(但是會把非同步併發的程式變成同步程式,不能併發,效能差)
    • 查詢當前mysql的隔離級別(預設是RR)
    select @@ tx_isolation;
    
    • 查詢當前是否自動提交資料

      select @@ autocommit;
      
    • 修改mysql配置檔案

      D:\MYSQL5.7\mysql-5.7.25-winx64\my.ini
      #系統預設的隔離級別(REPEATABLE-READ)
      transaction_isolation = READ-UNCOMMITTED
      #防止系統自動提交資料
      autocommit = 0
      #重啟mysql
      net stop mysql
      net start mysql
      
      1. 髒讀

        • READ-UNCOMMITTED
        • 先去調整設定,重啟mysql;嘗試在一個窗口裡通過事務,更改一條資料,開啟另外一條視窗嘗試讀取,會出現問題
      2. 不可重複讀

        #視窗1
        begin;
        update t1 set k1='abc' where id=1
        select * from t1;
        commit;
        
        #視窗2
        select * from t1;資料也跟著改了是不可重讀
        
      3. 幻讀

        #視窗1
        begin;
        insert into  t1 values(4,'c',50);
        select * from t1;
        commit;
        #視窗2
        select * from t1;數量也跟著增加是幻讀
        
      4. 通過二次提交commit,可以讓多使用者同步資料;

      5. 事務應用的技術(瞭解)

        • RR級別下,解決不可重讀,使用mvcc技術,生成最新的mysql的系統備份(快照),然後讀取快照
        • RR級別下,解決幻讀,gap 間隙鎖 next-lock 下一鍵鎖

關於約束的新增和刪除

  1. 新增、刪除 約束 not null

    #alter table 表名 modify 欄位名 型別
    alter table t1 modify id int not null
    alter table t1 nodify id int
    
  2. 新增、刪除 unique唯一索引

    #alter table 表名 add unique(id)
    alter table t1 add unique(id)
    alter table t1 drop index id
    
  3. 新增、刪除 primary key

    #alter table 表名 add primary key(id)
    alter table t1 add primary key(id)
    alter table t1 drop primary key
    
  4. 新增、刪除 foreign key 外來鍵(先通過desc表 找到外來鍵的名字,然後再刪)

    alter table student1 drop foreign key student1_ibkf_1#刪除
    alter table student1 add foreign key(classid) references class(id)#新增