一.索引,分頁性能,執行計劃,慢日誌html
(1)索引的種類,建立語句,名詞補充(最左前綴匹配,覆蓋索引,索引合併,局部索引等):python
import sys # http://www.cnblogs.com/wupeiqi/articles/5716963.html 武老師索引補充 ''' 索引種類: 單列: 1.普通索引 : 加速查找 2.主鍵索引 : 加速查找 + 不能爲空+ 惟一 3.惟一素銀 : 加速查找 + 惟一 多列: 4.聯合(組合)索引 : 1.聯合惟一 2.聯合不惟一 聯合主鍵索引 聯合惟一索引 聯合普通索引(本身取名來的) ''' #主鍵索引 #生成普通索引: # create index ix_name on userinfo(列名) #drop index ix_name on table_name #生成惟一索引: #create unique index index_name on table_name(field) #生成聯合索引: # create index ix_name on userinfo(列名,列名...) #drop index ix_name on table_name #局部索引: #create index index_name on table_name(列明(16)) 表示列名前16個字符作索引 #如下幾個類型必定要作局部索引: #1. Text類型 '''#最左前綴匹配 # create index ix_name_email on userinfo(name,email,lie3,lie4..); 多列仍是最左前綴 #設置普通聯合索引,仍是會以name爲準,只有帶上name做爲條件,才能查得快,只有email仍是慢 ''' #所以組合索引 效率比 索引合併效率高 #可是組合索引,由於有 最左前綴匹配。 # 要依據實際狀況去建立索引!!! ''' 兩種不是真實的索引,是概念: 覆蓋索引:在索引文件中直接獲取數據,(而不用去數據表再獲取其餘數據) 覆蓋索引:select email from userinfo where email = 'email213' 可是若是 select * 則還要去數據表中獲取其餘列數據 索引合併:把多個單列索引,合併使用 select * from userinfo where emai=xxx and id = xxx; (email和id都設置了索引) #局部索引: 若是字段先後有重複值,那麼重複值就不取,只取該字段不重複部分作索引 ''' #全文索引:生產過程當中不借助mysql,用第三方工具,知道就好 ''' 總結: 索引的種類1.主鍵索引,2.普通索引,3.惟一索引,4.聯合索引,5.覆蓋索引和索引合併 索引建立的命令語句 #特色:1.查找速度快,可是更刪改慢(索引不是越多越好!!!) 2.額外硬盤空間放索引的存儲特殊的數據結構:1.哈希索引 2.btree索引 3.索引要命中,纔有效果 #聯合索引:最左前綴匹配 #索引沒法命中的狀況 ''' #create table t1( id int auto_increment primary key, # num int, # name char(10), #unique 索引名 (num) #單列惟一索引 #index 索引名 (num) #建立普通索引 #unique 索引名 (num,name) #聯合惟一索引: 不能由兩行如出一轍的 num和name
#-- select * from userinfo where name='alex359613'; 3.379秒 # select * from userinfo where id = 359613; #id做爲索引 查詢只用了 0.063秒 #生成普通索引: # create index ix_name on userinfo(列名) #drop index ix_name on table_name #生成惟一索引: #create unique index index_name on table_name(field) #生成聯合索引: # create index ix_name on userinfo(列名,列名...) #drop index ix_name on table_name #局部索引: #create index index_name on table_name(列明(16)) 表示列名前16個字符作索引 #如下幾個類型必定要作局部索引: #1. Text類型 ''' 無索引:從前到後一次查找 索引: name 建立額外文件(某種格式存儲), name,email 建立額外文件(某種格式存儲), 當搜索的時候,先來這個文件裏找數據在哪一個文職,而後去表裏定位 ''' # create index ix_name_email on userinfo(name,email); #最左前綴匹配 #設置普通聯合索引,仍是會以name爲準,只有帶上name做爲條件,才能查得快,只查email仍是慢 ''' 索引種類 hash索引:建立了一個索引表,把全部的name都轉換爲hash值+這行所在的內存地址,而後直接根據地址,去找到數據 哈希表的值,和數據庫表裏的值,順序是不同的 缺點:取範圍速度沒那麼快。 好比咱們找id>3在普通表就很快找了,由於遍歷只要到3,可是哈希索引由於是亂序的因此這種狀況下反倒沒那麼快 優勢: 可是哈希索引在尋找單個值的時候,速度是很是快的 btree索引:二叉樹的格式,用二分法查找方法,應用較廣(innodb引擎)。 ''' #要想查找速度快 #創建索引:查詢快,增改刪變慢 #1.額外的文件,保存特殊的數據結構, #2.建立了索引,致使咱們 insert或者update或者delete的時候也要去更新索引,因此插入和更新速度會變慢 #3.命中索引:建立了要用,纔能有價值
#索引沒法命中的狀況 #執行計劃explain: 可是之後在公司的時候 若是忘記了如下狀況,能夠去sql裏面本身運行語句測試一下 # 不走索引的狀況,避免如下狀況 ''' - like '%xx' (生產過程當中數據量大會用到第三方工具) select * from tb1 where name like '%cn'; 關於like: 用戶量少的時候: 用like和佔位符模糊匹配 用戶量巨大的時候: 第三方工具 sifinks(發音) 他會把字段 存在文件裏, 好比:title字段 鎮化,增加率,省份.. 對應的id有 1,,4,5, 而後獲取到對應id後,再到 sql中進行 select * from userinfo where id in (...) - 使用函數 select * from tb1 where reverse(name) = 'wupeiqi'; 因此讓本身的字符串條件翻轉就好啦 - or select * from tb1 where nid = 1 or email = 'seven@live.com'; 特別的:當or條件中有未創建索引的列才失效,如下會走索引 select * from tb1 where nid = 1 or name = 'seven'; select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex' - 類型不一致 若是列是字符串類型,傳入條件是必須用引號引發來,否則... select * from tb1 where name = 999; 若是和數據表裏數據類型不一致,就會失效 #主鍵索引除外~~ - != select * from tb1 where name != 'alex' 特別的:若是是主鍵,則仍是會走索引 select * from tb1 where nid != 123 - > select * from tb1 where name > 'alex' 特別的:若是是主鍵或索引是整數類型,則仍是會走索引 select * from tb1 where nid > 123 select * from tb1 where num > 123 - order by select !email! from tb1 order by !name! desc; 當根據索引排序時候,選擇的映射若是不是索引,則不走索引 特別的:若是對主鍵排序,則仍是走索引: select * from tb1 order by nid desc; - 組合索引最左前綴 若是組合索引爲:(name,email) name and email -- 使用索引 name -- 使用索引 email -- 不使用索引 '''
import os '''打星號爲基礎中的基礎,要背下來 1.******* 避免使用select * (聯想覆蓋索引) 2.*******count(1)或者count(列),代替 count(*) 3.*******建立表的時 char 代替 varchar 4.表的字段順序固定長度字段優先 5.組合索引代替多個單列索引 (這個要根據實際狀況,若是單列查得多,仍是用單列好),注意有 最左前綴匹配 6.儘可能使用短索引: 局部索引,參見此day39 文件1 7.使用鏈接(join)來代替子查詢(Sub-Queries):mysql裏能夠先不用在乎這個,sql sever中有差異 8.連表時注意條件類型一致 9.*******索引散列值(重複少)不適合建索引,好比:性別這個列 '''
(2).limit分頁性能幾種方案mysql
import os ''' limit 數值越大越慢,好比 limit 300000,10 它會先掃描30萬行,而後再取下10行 ''' ''' 那要怎麼解決這個分頁問題呢: 1.不讓看 好比博客園,首頁最多隻能瀏覽 200頁的內容 2.索引表中掃描: 用到了覆蓋索引,可是速度仍是不快 select * from userinfo where id in ( select id from userinfo limit 200000,10) 3.較優解法: 結合python語句,記錄當前頁最大或最小id: 1.頁面只有上一頁和下一頁 下一頁: select * from userinfo where id > 200000 limit 10; 上一頁: select * from userinfo where id < 200000 order by id desc limit 10; 那好比 197 198 199 200 201 咱們網頁上是這麼顯示的 此時若是我在197 想跳轉到200頁怎麼操做呢?每頁10行 select * from userinfo where id > 200000 limit 10*(200-197),10; #大於200000後,從第30行開始,取10行 或者 select * from userinfo where id in (select id from (select * from userinfo where id > [當前頁maxid] limit 30) as N order by N.id desc limit 10 ); #大於200000後,取30行,設置臨時表,再從大到小排序,取前十行的id,再表中選擇 那若是沒有上下頁關聯,我就是想從第1頁跳轉到第1萬頁呢 這在sql中目前實現不了,只能慢慢等待掃描了。 有個想法是 between and select * from userinfo where id between 1 and 10; 可是要考慮到 id是否必定是連續的呢, 好比 delete from userinfo where id = 4; 那麼 此時1 - 10 就只有9條數據了 !!!*** 所以有個重要前提是 【limit的時候,必定要考慮到 id是不是連續的!!】 ''' #武老師博客的分頁代碼 ''' 每頁顯示10條: 當前 118 120, 125 倒序: 大 小 980 970 7 6 6 5 54 43 32 21 19 98 上一頁: select * from tb1 where nid < (select nid from (select nid from tb1 where nid < 當前頁最小值 order by nid desc limit 每頁數據 *【頁碼-當前頁】) A order by A.nid asc limit 1) order by nid desc limit 10; select * from tb1 where nid < (select nid from (select nid from tb1 where nid < 970 order by nid desc limit 40) A order by A.nid asc limit 1) order by nid desc limit 10; 下一頁: select * from tb1 where nid < (select nid from (select nid from tb1 where nid > 當前頁最大值 order by nid asc limit 每頁數據 *【當前頁-頁碼】) A order by A.nid asc limit 1) order by nid desc limit 10; select * from tb1 where nid < (select nid from (select nid from tb1 where nid > 980 order by nid asc limit 20) A order by A.nid desc limit 1) order by nid desc limit 10; '''
(3).執行計劃介紹:程序員
import os #執行計劃 #預估一條sql語句的執行時間 ''' mysql> explain select * from userinfo \G; *************************** 1. row *************************** id: 1 #註釋1 select_type: SIMPLE :代指簡單查詢 table: userinfo #註釋2 partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 2837841 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec) ''' #註釋1: #id:1 標識符,代指如今預估哪一條sql,和順序無關. 這裏只有一句因此就1 #select * from tb where id in (select id from tb2); 這裏就有2句sql了 #註釋2: #ALL : 全表掃描 #可是all不必定慢,好比 select * from tb limit 1; #range : where id > 3 #const : where id = 3 #constant #ref : 經過索引查詢 #總結:查詢時的訪問方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const #具體各個值代指什麼,見最下方 ''' #那若是查詢的字段有 索引,他是怎麼預估的呢 mysql> explain select * from userinfo where name='alex465456' \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: userinfo partitions: NULL type: ref possible_keys: ix_name_email key: ix_name_email key_len: 91 ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec) '''
''' type 查詢時的訪問方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const ALL 全表掃描,對於數據表從頭至尾找一遍 select * from tb1; 特別的:若是有limit限制,則找到以後就不在繼續向下掃描 select * from tb1 where email = 'seven@live.com' select * from tb1 where email = 'seven@live.com' limit 1; 雖然上述兩個語句都會進行全表掃描,第二句使用了limit,則找到一個後就再也不繼續掃描。 INDEX 全索引掃描,對索引從頭至尾找一遍 select nid from tb1; RANGE 對索引列進行範圍查找 select * from tb1 where name < 'alex'; PS: between and in > >= < <= 操做 注意:!= 和 > 符號 INDEX_MERGE 合併索引,使用多個單列索引搜索 select * from tb1 where name = 'alex' or nid in (11,22,33); REF 根據索引查找一個或多個值 select * from tb1 where name = 'seven'; EQ_REF 鏈接時使用primary key 或 unique類型 select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid; CONST 常量 表最多有一個匹配行,由於僅有一行,在這行的列值可被優化器剩餘部分認爲是常數,const表很快,由於它們只讀取一次。 select nid from tb1 where nid = 2 ; SYSTEM 系統 表僅有一行(=系統表)。這是const聯接類型的一個特例。 select * from (select nid from tb1 where nid = 1) as A; '''
(4).慢日誌記錄:sql
import os #DBA工做 #在mysql的服務端進行記錄 ''' mysql> show variables like '%quer%'; +----------------------------------------+---------------------------------------------+ | Variable_name | Value | +----------------------------------------+---------------------------------------------+ | binlog_rows_query_log_events | OFF | | ft_query_expansion_limit | 20 | | have_query_cache | NO | | log_queries_not_using_indexes | OFF # 語句未使用索引 | | log_throttle_queries_not_using_indexes | 0 | | long_query_time | 10.000000 #運行時間大於10秒 則記錄 | | query_alloc_block_size | 8192 | | query_prealloc_size | 8192 | | slow_query_log | OFF # 慢查詢日誌是否開啓 | | slow_query_log_file #慢日誌目錄 | D:\mysql-8.0.12-winx64\data\Gkx-PC-slow.log | +----------------------------------------+---------------------------------------------+ 10 rows in set, 1 warning (0.00 sec) 注:查看當前配置信息: show variables like '%query%' 修改當前配置: set global 變量名 = 值 set global slow_query_log = ON; ''' #配置: #以上是依據內存進行設置: 設置完立刻生效 #還能夠依據配置文件: mysqld # mysqld --defaults-file='D:\mysql-8.0.12-winx64\my.ini' # 就是咱們最早設置的 my.ini 啦,因此能夠告訴它這個ini配置文件的路徑,而後咱們在ini裏寫好配置便可 #好比所在 d:/my.ini 而後在這個 ini文件裏 把slow_query_log = ON; #想要設置的變量寫進去 # slow_query_log = ON # slow_query_log_file = '路徑'... ''' 修改配置文件前,必定要備份 修改配置文件後,要重啓才能生效 '''
二.視圖數據庫
三.觸發器網絡
# 定義 : 對某個表進行【增/刪/改】操做的先後若是但願觸發某個特定的行爲時,可使用觸發器,(能夠插入多張表也沒問題) # 觸發器用於定製用戶對錶的行進行【增/刪/改】先後的行爲。 #注意觸發器是沒有 select 的引起行爲的,只有 insert,delete,update #若是tb1 在一行語句插入多行數據,那麼觸發器也會對應插入多行數據 # 要建立觸發器前,應該先修改分隔符 delimiter #insert into tb (....) # -- delimiter // # -- create trigger t1 BEFORE INSERT on student for EACH ROW # -- BEGIN # -- INSERT into teacher(tname) values(NEW.sname); #由於不修改的話,執行到這裏的分號語句就結束了,下面的執行不到 # -- INSERT into teacher(tname) values(NEW.sname); #NEW.sname 表示你插入tb1 的那條字段的新數據 # -- INSERT into teacher(tname) values(NEW.sname); # -- INSERT into teacher(tname) values(NEW.sname); # -- END // # -- delimiter ; #修改完記得改回來 # -- insert into student(gender,class_id,sname) values('女',1,'陳濤'),('女',1,'張根'); # -- NEW,代指新數據 (用於 insert) # -- OLD,代指老數據 (用於 delete / update) #總結觸發器以下: # # 插入前 # CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW # BEGIN # INSERT into teacher(tname) values(NEW.sname); (在插入數據以前,要作這個操做)也就是你每往tb1插入一條數據,tb2也會插入數據 # END #若是tb1 在一行語句插入多行數據,那麼觸發器也會對應插入多行數據 # # # 插入後 # CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW # BEGIN # ... # END # # # 刪除前 # CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW # BEGIN # ... # END # # # 刪除後 # CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW # BEGIN # ... # END # # # 更新前 # CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW # BEGIN # ... # END # # # 更新後 # CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW # BEGIN # ... # END
四.函數session
#MySQL也有 內置函數 和 自定義函數 :函數是一定有返回值的 # select now() # 老師博客: http://www.cnblogs.com/wupeiqi/articles/5713323.html # 官方解釋:https://dev.mysql.com/doc/refman/5.7/en/functions.html #時間格式化 #select DATE_FORMAT(時間字段,'%Y-%m'),count(1) from table_name group by DATE_FORMAT(時間字段,'%Y-%m') #格式相似 time模塊 #自定義函數: # delimiter \\ # create function f1( # i1 int, # i2 int) #傳參 # returns int #返回值數據類型 # BEGIN # declare num int; #必定不能寫 select # set num = i1 + i2; # return(num); # END \\ # delimiter ; #刪除函數:drop function func_name; #執行函數: select f1(0,100) ; 輸出 100 # # 獲取返回值 # declare @i VARCHAR(32); # select UPPER('alex') into @i; # SELECT @i; # # # 在查詢中使用 # select f1(11,nid) ,name from tb2;
#部份內置函數—字符串相關的 # CHAR_LENGTH(str) # 返回值爲字符串str 的長度,長度的單位爲字符。一個多字節字符算做一個單字符。 # 對於一個包含五個二字節字符集, LENGTH()返回值爲 10, 而CHAR_LENGTH()的返回值爲5。 # # CONCAT(str1,str2,...) # 字符串拼接 # 若有任何一個參數爲NULL ,則返回值爲 NULL。 # CONCAT_WS(separator,str1,str2,...) # 字符串拼接(自定義鏈接符) # CONCAT_WS()不會忽略任何空字符串。 (然而會忽略全部的 NULL)。 # # CONV(N,from_base,to_base) # 進制轉換 # 例如: # SELECT CONV('a',16,2); 表示將 a 由16進制轉換爲2進制字符串表示 # # FORMAT(X,D) # 將數字X 的格式寫爲'#,###,###.##',以四捨五入的方式保留小數點後 D 位, 並將結果以字符串的形式返回。若 D 爲 0, 則返回結果不帶有小數點,或不含小數部分。 # 例如: # SELECT FORMAT(12332.1,4); 結果爲: '12,332.1000' # INSERT(str,pos,len,newstr) # 在str的指定位置插入字符串 # pos:要替換位置其實位置 # len:替換的長度 # newstr:新字符串 # 特別的: # 若是pos超過原字符串長度,則返回原字符串 # 若是len超過原字符串長度,則由新字符串徹底替換 # INSTR(str,substr) # 返回字符串 str 中子字符串的第一個出現位置。 # # LEFT(str,len) # 返回字符串str 從開始的len位置的子序列字符。 # # LOWER(str) # 變小寫 # # UPPER(str) # 變大寫 # # LTRIM(str) # 返回字符串 str ,其引導空格字符被刪除。 # RTRIM(str) # 返回字符串 str ,結尾空格字符被刪去。 # SUBSTRING(str,pos,len) # 獲取字符串子序列 # # LOCATE(substr,str,pos) # 獲取子序列索引位置 # # REPEAT(str,count) # 返回一個由重複的字符串str 組成的字符串,字符串str的數目等於count 。 # 若 count <= 0,則返回一個空字符串。 # 若str 或 count 爲 NULL,則返回 NULL 。 # REPLACE(str,from_str,to_str) # 返回字符串str 以及全部被字符串to_str替代的字符串from_str 。 # REVERSE(str) # 返回字符串 str ,順序和字符順序相反。 # RIGHT(str,len) # 從字符串str 開始,返回從後邊開始len個字符組成的子序列 # # SPACE(N) # 返回一個由N空格組成的字符串。 # # SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len) # 不帶有len 參數的格式從字符串str返回一個子字符串,起始於位置 pos。帶有len參數的格式從字符串str返回一個長度同len字符相同的子字符串,起始於位置 pos。 使用 FROM的格式爲標準 SQL 語法。也可能對pos使用一個負值。倘若這樣,則子字符串的位置起始於字符串結尾的pos 字符,而不是字符串的開頭位置。在如下格式的函數中能夠對pos 使用一個負值。 # # mysql> SELECT SUBSTRING('Quadratically',5); # -> 'ratically' # # mysql> SELECT SUBSTRING('foobarbar' FROM 4); # -> 'barbar' # # mysql> SELECT SUBSTRING('Quadratically',5,6); # -> 'ratica' # # mysql> SELECT SUBSTRING('Sakila', -3); # -> 'ila' # # mysql> SELECT SUBSTRING('Sakila', -5, 3); # -> 'aki' # # mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2); # -> 'ki' # # TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str) # 返回字符串 str , 其中全部remstr 前綴和/或後綴都已被刪除。若分類符BOTH、LEADIN或TRAILING中沒有一個是給定的,則假設爲BOTH 。 remstr 爲可選項,在未指定狀況下,可刪除空格。 # # mysql> SELECT TRIM(' bar '); # -> 'bar' # # mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx'); # -> 'barxxx' # # mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx'); # -> 'bar' # # mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz'); # -> 'barx' # # 部份內置函數
最經常使用的:字符串去重,拼接,取子序列,時間的操做
五.存儲過程數據結構
import time ''' #存儲過程,相比 視圖,觸發器,函數 更爲重要 #存儲過程在服務端的mysql(視圖,觸發器,函數也是),客戶端只要知道存儲過程的名字就能夠了 #定義: 保存在mysql上的一個別名 ---> 一串SQL語句,使用別名就能查到語句 #沒有返回值的概念 有三個參數類型 in(傳進去要使用的) out(傳進去要拿出來的) inout(傳進去既可使用也能夠拿出來的) ''' #和視圖的區別: #視圖:別名代指臨時表,只能select,動態的顯示錶,並不建議修改 #存儲過程:存了不少sql語句,比視圖多。調用更簡單,實現功能更多 #用來替代sql語句的,讓程序員不在寫程序語句了 #直接調用 存儲過程 別名,就能夠直接使用sql語句了 #將sql語句和代碼進行解耦了,好比網絡傳輸只須要傳別名 #程序員寫sql,而後交給dba審覈 #慢日誌:pymysql 能夠記錄執行較慢的 sql語句。 # 方式一: # mysql:存儲過程 # 程序:調用存儲過程 # 方式二: # mysql:啥也不作 #程序:寫SQL語句 #方式三: #mysql:啥也不作 #程序:寫類和對象 ---> 轉化爲 SQL語句 #存儲過程初識: # 一 不帶參數 # delimiter // # create procedure p1() # begin # select * from student; # insert into teacher(tname) values('ct'); # end // # delimiter ; #執行procedure : call p1(); #cursor.callproc('p1') #二 帶參數的:in (傳進去使用的) 參數表示有 int out inout # delimiter // # create procedure p2( # in n1 int, # in n2 int # ) # begin # select * from student where sid between n1 and n2; # # end // # delimiter ; # 執行procedure : call p1(12,2); # cursor.callproc('p2',(12,2)) ''' #三. 帶參數的:out (傳進去後要拿出來的) 參數表示有 int out inout # delimiter // # create procedure p3( # in n1 int, # out n2 int #n2必須是變量 # ) # begin # set n2 = 11111; # select * from student where sid > n1; # # end // # delimiter ; # 執行procedure : # set @v1 = 1; # call p3(12,@v1); 此時 n2 做爲out類型,要傳一個變量,而後能夠在外部再獲取到這個變量 # select @v1; # cursor.callproc('p2',(12,2)) 首先拿結果集 # cursor.execute('select @_p3_0,@_p3_1') # ret = cursor.fetchone();print(ret)------> ((12,11111))----》((n1的值,n2修改後的值)) #mysql中有一個session的概念 # set @v1 = 0; #表示建立了一個 session級別的變量 v1 . 【@】相似python中的 global # # 執行procedure : call p3(12,@v1); #而後再使用 @v1的時候,@v1值就變爲了 11111 --> (select @v1;) ''' # 特性======> #1.可傳參 in out inout #2.MySQL中用call調用,pymysql用 cursor.callproc(procedure,(arg1,arg2..)) #3.沒有返回值,可是能夠用 out 僞造一個返回值 ''' 爲何有結果集又有out僞造的返回值? out 返回值,通常狀況下是:用於標識存儲過程當中的執行結果 好比返回 1,2,3 1:成功 2:失敗 3:一部分紅功 語句1執行 執行完 set n1 =1 表示成功 語句2執行 執行完 set n2 =2 表示失敗..... '''
import sys #1.無參 2.帶參數in 3.帶參數 in out # #接下來第四種: 事務:原子性操做 # 在pymysql中能夠進行 try一下,若是報錯,則回滾 # ~~~~~~~~~~中文描述 # delimiter // # create procedure p4( # out status int # ) # BEGIN # 1. 聲明若是出現異常則執行{ # set status = 1; # rollback; # } # # 開始事務 # -- 由秦兵帳戶減去100 # -- 方少偉帳戶加90 # -- 張根帳戶加10 # commit; # 結束 # set status = 2; ''' #接下來第四種: 事務:原子性操做 在pymysql中能夠進行 try一下,若是報錯,則回滾 代碼以下: delimiter \\ create PROCEDURE p4( OUT p_return_code tinyint ) BEGIN DECLARE exit handler for sqlexception #若是出現異常,執行下面begin裏的語句 # https://www.cnblogs.com/datoubaba/archive/2012/06/20/2556428.html BEGIN -- ERROR set p_return_code = 1; #錯誤返回1 rollback; END; START TRANSACTION; #開始事物 DELETE from tb1; insert into tb2(name)values('seven'); COMMIT; -- SUCCESS set p_return_code = 2; #正確返回2 END\\ delimiter ; ''' #第四代碼:
#防 sql注入 #1.pymysql 程序級別去避免 #2.動態的存儲過程 #第五: #遊標:老師沒講 #第六: # 動態的執行 SQL ''' 6. 動態執行SQL(防SQL注入) delimiter // create procedure p7( in tpl varchar(255), in arg int ) begin 1. 預檢測某個東西 SQL語句合法性 2. SQL =格式化 tpl + arg 3. 執行SQL語句 set @xo = arg; #arg 要賦值給一個 session變量 PREPARE xxx FROM 'select * from student where sid > ?'; EXECUTE xxx USING @xo; DEALLOCATE prepare prod; end // delimter ; # call p7("select * from tb where id > ?",9) ''' #真代碼以下: # ===> # # delimiter \\ # CREATE PROCEDURE p8 ( # in nid int # ) # BEGIN # set @nid = nid; # PREPARE prod FROM 'select * from student where sid > ?'; # EXECUTE prod USING @nid; # DEALLOCATE prepare prod; # END\\ # delimiter ;
import pymysql conn = pymysql.connect(host='localhost',user='root',password='gkx321',database='sql_homework',charset='utf8') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.callproc('p3',(12,2)) #n1是12,無所謂n2是多少,不影響 ret = cursor.fetchall() print(ret) #out的值要這麼獲取,固定寫法 cursor.execute('select @_p3_0,@_p3_1') #能夠只寫一個 0獲取n1,1獲取n2 ret = cursor.fetchall() print(ret) ''' 爲何格式是這樣呢,由於pymysql內部幫咱們作了這樣子的操做 set @ _p3_0 = 12 set @ _p3_1 = 2 call p3( @ _p3_0,@_p3_1) select @ _p3_0,@_p3_1 ''' # cursor.execute('select * from teacher') # ret = cursor.fetchall() # print(ret) cursor.close() conn.close()
存儲過程總結:
1.無參數
2.有參數 in
3.有參數 in out
爲何有結果集又要有out? ----> 用於標識存儲過程當中的執行結果
4.事務
5.遊標
6.動態執行sql(防sql注入)
數據庫相關操做:
1.sql語句:本身寫sql所有都能實現
想要利用函數的時候,先找mysql內置函數,找不到再本身寫 #函數可能會形成性能低:又索引,函數不會使用索引
-- select xx() from xx;
最經常使用的:字符串去重,拼接,取子序列
時間的操做
2.利用mysql內部提供的功能:視圖,觸發器,函數,存儲過程