1. 程式人生 > 其它 >MySQL檢視/觸發器/事務/儲存過程/函式/流程控制/索引

MySQL檢視/觸發器/事務/儲存過程/函式/流程控制/索引

檢視

'''
    什麼是檢視?
        檢視就是通過查詢得到一張虛擬表,然後儲存下來,下次可以直接使用
        其實檢視也是表
    為什麼要用檢視?
        如果要頻繁的操作一張虛擬表(拼表組成的),你就可以製作成檢視,後續直接操作
    如何操作?
        固定語法
            create view 表名 as 虛擬表查詢sql語句
        具體操作
            create view new_table as select * from t1 inner join t2 on t1.id = t2.id;
    注意
        1 建立檢視在硬碟上只會有表結構,沒有表資料(資料還是來自於之前的表)
        2 檢視一般只用來查詢,裡面的資料不要進行修改,可能會影響真正的表
    檢視到底使用頻率高不高呢?
        不高
        當你建立了很多檢視後,會造成表不好維護
    檢視瞭解即可,基本不用
'''

觸發器

'''
    在滿足對錶資料進行增,刪,改的情況下,自動觸發的功能,稱之為觸發器
    使用觸發器可以幫助我們實現監控,日誌,自動處理異常等等...
    觸發器可以在六種情況下自動觸發,增前/增後/刪前/刪後/改前/改後
    基本語法結構
        create trigger 觸發器的名字 before/after insert/update/delete on 表名 for each row begin sql語句 end
    具體使用,針對觸發器的名字,我們通常需要做到見名知意
        針對增
            create trigger tri_before_insert_t1 before insert on t1 for each row begin sql語句 end
            create trigger tri_after_insert_t1 after insert on t1 for each row begin sql語句 end
        針對刪除和修改,書寫格式一致
    ps:修改MySQL預設的語句結束符,只作用於當前cmd視窗
        delimiter $$ 將預設的結束符;改為$$
        delimiter ;
    案例
        create table cmd(
            id int primary key auto_increment,
            user char(32),
            priv char(10),
            cmd char(64),
            sub_time datetime, # 提交時間
            sucess enum('yes','no')
        );
        create table errlog(
            id int primary key auto_increment,
            err_cmd char(64),
            err_time datetime
        );
            當cmd表中的記錄success欄位是no,那麼就觸發觸發器的執行去errlog表中插入資料,NEW指代的就是一條條資料物件
                delimiter $$
                create tirgger tri_after_insert_cmd after insert on cmd for each row begin
                    if NEW.success='no' then
                        insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time);
                    end if;
                end $$
                delimiter ;
        向cmd表插入資料
            insert into cmd(
                user,
                priv,
                cmd,
                sub_time,
                success
            )
            values
                ('jason','0755','ls-l /etc',NOW(),'yes'),
                ('jason','0755','cat /etc/passwd',NOW(),'no'),
                ('jason','0755','useradd xxx',NOW(),'no'),
                ('jason','0755','ps aux',NOW(),'yes');
    刪除觸發器
        drop trigger tri_after_insert_cmd;
'''

事務

'''
    什麼是事務?
        開啟一個事務可以包含多條sql語句,這些sql語句要麼同時成功,要麼一個都別想成功,稱之為事務的原子性
    事務的作用
        保證了對資料操作的安全性
        eg:還錢的例子
            A用銀行卡給B支付寶轉賬1000
                1 將A銀行卡賬戶的資料減1000
                2 將B支付寶賬戶的資料加1000
                3 由於網路原因,銀行卡減了1000,而支付寶沒有加1000
            你在操作多條資料的時候,可能會出現某幾條操作不成功的情況
    事務的四大特性
        ACID
        A:原子性 atomicity
            一個事務是一個不可分割的單位,事務中包含的諸多操作,要麼同時成功,要麼同時失敗
        C:一致性 consistency
            事務必須是使資料庫從一個一致性的狀態變到另外一個一致性的狀態,一致性跟原子性是密切相關的
        I:隔離性 isolation
            一個事務的執行不能被其它事務干擾。即一個事務內部的操作及使用到的資料對併發的其它事務是隔離的,併發執行的事務之間也是互相不干擾的
        D:永續性 durability
            也叫'永久性'。一個事務一旦提交成功執行成功,那麼它對資料庫中資料的修改應該是永久的,接下來的其它操作或者故障不應該對其有任何的影響
    如何使用事務
        事務相關的關鍵字
            1 開啟事務
                start transaction;
            2 回滾(回到事務執行之前的狀態)
                rollback;
            3 確認(確認之後就無法回滾了)
                commit;
    模擬轉賬功能
        create table user(
            id int primary key auto_increment,
            name char(16),
            balance int
        );
        insert into user(name,balance) values('jason',1000),('egon',1000),('tank',1000);
        1 先開啟事務
            start transaction;
        2 多條sql語句
            update user set balance=900 where name='jason';
            update user set balance=1010 where name='egon';
            update user set balance=1090 where name='tank';
        3 回滾
            rollback;
        3.1 或確認
            commit;
    總結
        當你想讓多條sql語句保持一致性,要麼同時成功,要麼同時失敗,你就應該考慮使用事務
'''

儲存過程

'''
    儲存過程就類似於python中的自定義函式,它的內部包含了一系列可以執行的sql語句,儲存過程存放於MySQL服務端中,你可以直接通過呼叫儲存過程觸發內部sql語句的執行
    基本使用
        create procedure 儲存過程的名字(形參1,形參2,...)
            begin
                sql程式碼
            end
        呼叫:
            call 儲存過程的名字();
    三種開發模型
        第一種
            應用程式:程式設計師寫程式碼開發
            MySQL:提前編寫好儲存過程,供應用程式呼叫
            好處:開發效率提升了,執行效率也上去了
            壞處:考慮到人為因素,跨部門溝通的問題,後續儲存過程的擴充套件性太差
        第二種
            應用程式:程式設計師寫程式碼開發,涉及到資料庫操作也自己動手寫
            優點:擴充套件性很高
            缺點:開發效率降低,編寫sql語句太過繁瑣,而且後續還需要考慮sql優化的問題
        第三種
            應用程式:只寫程式程式碼,不寫sql語句,基於別人寫好的操作mysql的python框架直接呼叫操作即可,如ORM框架
            優點:開發效率比上面兩種情況都要高
            缺點:語句的擴充套件性差,可能會出現效率低下的問題
    儲存過程具體演示
        delimiter $$
        create procedure p1(
            in m int, # in只進不出,m不能返回
            in n int,
            out res int, # out該形參可以返回出去
        )
            begin
                select tname from teacher where tid>m and tid<n;
                set res=666; # 將res變數修改,用來標識當前的儲存過程程式碼確實執行了
            end $$
        delimiter ;
            # 針對形參res不能直接傳資料,應該傳一個變數名
            # 定義變數 set @ret=10;
            # 檢視變數對應的值 select @ret;
        set @ret=10;
        call p1(1,5,@ret);
        select @ret; # 結果為666
    在pymysql模組種如何呼叫儲存過程呢?
        import pymysql
        conn = pymysql.connect(
            host = '127.0.0.1',
            port = 3306,
            user = 'root',
            passwd = '123456',
            db = 'db666', # 有設定儲存過程的庫
            charset = 'utf8',
            autocommit = True
        )
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        # 呼叫儲存過程
        cursor.callproc('p1',(1,5,10))
        """
        @_p1_0=1
        @_p1_1=5
        @_p1_2=10
        """
        # print(cursor.fetchall())
        cursor.execute('select @_p1_2;')
        print(cursor.fetchall()) # [{'@_p1_2': 666}]
'''

函式

'''
    跟儲存過程是有區別的,儲存過程是自定義函式,函式就類似於是內建函式,NOW()用來獲取當前時間
    create table blog(
        id int primary key auto_increment,
        name char(32),
        sub_time datetime
    );
    insert into blog(name,sub_time) values
        ('第一篇','2015-03-01 11:31:21'),
        ('第一篇','2015-03-11 14:31:21'),
        ('第一篇','2016-09-01 10:39:41'),
        ('第一篇','2016-07-22 09:23:21'),
        ('第一篇','2016-07-23 10:11:11'),
        ('第一篇','2015-07-25 11:21:31'),
        ('第一篇','2017-03-01 15:33:21'),
        ('第一篇','2017-03-01 17:32:21'),
        ('第一篇','2017-03-01 18:31:21');
    select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');
'''

流程控制

'''
    if判斷
        delimiter //
        create procedure proc_if()
        begin
            declare i int default 0;
            if i = 1 then
                select 1;
            elseif i = 2 then
                select 2;
            else
                select 7;
            end if;
        end //
        delimiter ;
    while迴圈
        delimiter //
        create procedure proc_while()
        begin
            declare num int;
            set num = 0;
            while num<10 do
                select num;
                set num = num + 1;
            end while;
        end //
        delimiter ;
'''

索引

'''
    ps:資料都是存在於硬碟上的,查詢資料不可避免的需要進行IO操作
    索引:就是一種資料結構,類似於書的目錄。意味著以後在查詢資料的時候應該先找目錄再找資料,而不是一頁一頁的翻書,從而提升查詢速度降低IO操作
    索引在MySQL中也叫'鍵',是儲存引擎用於快速查詢記錄的一種資料結構(innodb/myisam)
        primary key
        unique key
        index key
        注意:foreign key不是用來加速查詢用的,不在我們研究範圍之內
    上面的三種key,前面兩種除了可以增加查詢速度之外,各自還具有約束條件,而最後一種index key沒有任何的約束條件,只是用來幫助你快速查詢資料
    本質
        通過不斷的縮小想要的資料範圍篩選出最終的結果,同時將隨機事件(一頁一頁的翻)變成順序事件(先找目錄,再找資料);也就是說有了索引機制,我們可以總是用一種固定的方式查詢資料
    一張表中可以有多個索引(多個目錄)
    索引雖然能夠幫助你加快查詢速度,但是也有缺點
        1 當表中有大量資料存在的前提下,建立索引速度會很慢
        2 在索引建立完畢之後,對錶的查詢效能會大幅度的提升,但是寫的效能也會大幅度的降低
        結論:索引不要隨意的建立!!!
    b+樹
        只有葉子節點存放的是真實的資料,其它節點存放的是虛擬資料,僅僅是用來之路的
        樹的層級越高,查詢資料所需要經歷的步驟就越多(樹有幾層,查詢資料就需要幾步)
        為什麼建議將id欄位作為索引
            佔得空間少,一個磁碟塊能夠儲存的資料多,那麼就降低了樹的高度,從而減少查詢次數
    聚集索引(primary key)
        聚集索引指的就是主鍵
            innodb 只有兩個檔案,直接將主鍵存放在了idb表中(資料表)
            myisam 三個檔案,單獨將索引存在一個檔案
    輔助索引(unique,index)
        查詢資料的時候,不可能一直使用到主鍵,也有可能會用到name,password等其它欄位,那麼這個時候沒有辦法利用聚集索引。這時可以根據情況給其他欄位設定輔助索引(也是一個b+樹)
        葉子節點存放的是資料對應的主鍵值
            先按照輔助索引拿到資料的主鍵值,之後還是需要去主鍵的聚集索引裡面查詢資料
    覆蓋索引
        在輔助索引的葉子節點就已經拿到了想要的資料
            # 給name設定輔助索引
                select name from user where name = 'jason';
            # 非覆蓋索引
                select age from user where name = 'jason';
'''
while True: print('studying...')