日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL 之视图、 触发器、事务、存储过程、内置函数、流程控制、索引(二)

發(fā)布時間:2024/9/30 数据库 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL 之视图、 触发器、事务、存储过程、内置函数、流程控制、索引(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

繼上文

--------------------------------------------------------------------注:如果你對python感興趣,我這有個學習Python基地,里面有很多學習資料,感興趣的+Q群:895817687 --------------------------------------------------------------------- 存儲過程與事務使用的舉例delimiter // create procedure p5( -- 創(chuàng)建存儲過程p5out p_return_code tinyint ) begin-- 這里表示如果捕獲到異常,則執(zhí)行下面set p_return_code = 1并且回滾操作declare exit handler for sqlexceptionbegin-- ERRORset p_return_code = 1;rollback;end;-- 這里表示如果捕獲sql警告,則執(zhí)行下面set p_return_code = 2并且回滾操作declare exit handler for sqlwarningbegin-- WARNINGSset p_return_code = 2;rollback;end;start transaction; # 開始啟用事務update user set balance=900 where id =1;update user set balance=1010 where id = 2;update user set balance=1090 where id =3;commit; # 如果沒有出現異?;蛘呔婢蜁^續(xù)執(zhí)行提交語句-- successset p_return_code = 0; -- 代表執(zhí)行成功 end // delimiter ;

五、函數

  • 注意! 函數中不要寫sql語句(否則會報錯),函數僅僅只是一個功能,是一個在sql中被應用的功能
    若要想在begin…end…中寫sql,請用存儲過程
  • MySQL中提供了許多內置函數,例如:
一、數學函數ROUND(x,y)返回參數x的四舍五入的有y位小數的值RAND()返回0到1內的隨機值,可以通過提供一個參數(種子)使RAND()隨機數生成器生成一個指定的值。二、聚合函數(常用于GROUP BY從句的SELECT查詢中)AVG(col)返回指定列的平均值COUNT(col)返回指定列中非NULL值的個數MIN(col)返回指定列的最小值MAX(col)返回指定列的最大值SUM(col)返回指定列的所有值之和GROUP_CONCAT(col) 返回由屬于一組的列值連接組合而成的結果 三、字符串函數CHAR_LENGTH(str)返回值為字符串str 的長度,長度的單位為字符。一個多字節(jié)字符算作一個單字符。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)變大寫REVERSE(str)返回字符串 str ,順序和字符順序相反。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'四、日期和時間函數CURDATE()或CURRENT_DATE() 返回當前的日期CURTIME()或CURRENT_TIME() 返回當前的時間DAYOFWEEK(date) 返回date所代表的一星期中的第幾天(1~7)DAYOFMONTH(date) 返回date是一個月的第幾天(1~31)DAYOFYEAR(date) 返回date是一年的第幾天(1~366)DAYNAME(date) 返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);FROM_UNIXTIME(ts,fmt) 根據指定的fmt格式,格式化UNIX時間戳tsHOUR(time) 返回time的小時值(0~23)MINUTE(time) 返回time的分鐘值(0~59)MONTH(date) 返回date的月份值(1~12)MONTHNAME(date) 返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);NOW() 返回當前的日期和時間QUARTER(date) 返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);WEEK(date) 返回日期date為一年中第幾周(0~53)YEAR(date) 返回日期date的年份(1000~9999)重點:DATE_FORMAT(date,format) 根據format字符串格式化date值mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');-> 'Sunday October 2009'mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');-> '22:23:00'mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',-> '%D %y %a %d %m %b %j');-> '4th 00 Thu 04 10 Oct 277'mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',-> '%H %k %I %r %T %S %w');-> '22 22 10 10:23:00 PM 22:23:00 00 6'mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');-> '1998 52'mysql> SELECT DATE_FORMAT('2006-06-00', '%d');-> '00'五、加密函數MD5() 計算字符串str的MD5校驗和PASSWORD(str) 返回字符串str的加密版本,這個加密過程是不可逆轉的,和UNIX密碼加密過程使用不同的算法。六、控制流函數 CASE WHEN[test1] THEN [result1]...ELSE [default] END如果testN是真,則返回resultN,否則返回defaultCASE [test] WHEN[val1] THEN [result]...ELSE [default]END 如果test和valN相等,則返回resultN,否則返回defaultIF(test,t,f) 如果test是真,返回t;否則返回fIFNULL(arg1,arg2) 如果arg1不是空,返回arg1,否則返回arg2NULLIF(arg1,arg2) 如果arg1=arg2返回NULL;否則返回arg1 七、控制流函數小練習 #7.1、準備表 /* Navicat MySQL Data TransferSource Server : localhost_3306 Source Server Version : 50720 Source Host : localhost:3306 Source Database : studentTarget Server Type : MYSQL Target Server Version : 50720 File Encoding : 65001Date: 2018-01-02 12:05:30 */SET FOREIGN_KEY_CHECKS=0;-- ---------------------------- -- Table structure for course -- ---------------------------- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` (`c_id` int(11) NOT NULL,`c_name` varchar(255) DEFAULT NULL,`t_id` int(11) DEFAULT NULL,PRIMARY KEY (`c_id`),KEY `t_id` (`t_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of course -- ---------------------------- INSERT INTO `course` VALUES ('1', 'python', '1'); INSERT INTO `course` VALUES ('2', 'java', '2'); INSERT INTO `course` VALUES ('3', 'linux', '3'); INSERT INTO `course` VALUES ('4', 'web', '2');-- ---------------------------- -- Table structure for score -- ---------------------------- DROP TABLE IF EXISTS `score`; CREATE TABLE `score` (`id` int(11) NOT NULL AUTO_INCREMENT,`s_id` int(10) DEFAULT NULL,`c_id` int(11) DEFAULT NULL,`num` double DEFAULT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of score -- ---------------------------- INSERT INTO `score` VALUES ('1', '1', '1', '79'); INSERT INTO `score` VALUES ('2', '1', '2', '78'); INSERT INTO `score` VALUES ('3', '1', '3', '35'); INSERT INTO `score` VALUES ('4', '2', '2', '32'); INSERT INTO `score` VALUES ('5', '3', '1', '66'); INSERT INTO `score` VALUES ('6', '4', '2', '77'); INSERT INTO `score` VALUES ('7', '4', '1', '68'); INSERT INTO `score` VALUES ('8', '5', '1', '66'); INSERT INTO `score` VALUES ('9', '2', '1', '69'); INSERT INTO `score` VALUES ('10', '4', '4', '75'); INSERT INTO `score` VALUES ('11', '5', '4', '66.7');-- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` (`s_id` varchar(20) NOT NULL,`s_name` varchar(255) DEFAULT NULL,`s_age` int(10) DEFAULT NULL,`s_sex` char(1) DEFAULT NULL,PRIMARY KEY (`s_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES ('1', '魯班', '12', '男'); INSERT INTO `student` VALUES ('2', '貂蟬', '20', '女'); INSERT INTO `student` VALUES ('3', '劉備', '35', '男'); INSERT INTO `student` VALUES ('4', '關羽', '34', '男'); INSERT INTO `student` VALUES ('5', '張飛', '33', '女');-- ---------------------------- -- Table structure for teacher -- ---------------------------- DROP TABLE IF EXISTS `teacher`; CREATE TABLE `teacher` (`t_id` int(10) NOT NULL,`t_name` varchar(50) DEFAULT NULL,PRIMARY KEY (`t_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of teacher -- ---------------------------- INSERT INTO `teacher` VALUES ('1', '大王'); INSERT INTO `teacher` VALUES ('2', 'alex'); INSERT INTO `teacher` VALUES ('3', 'egon'); INSERT INTO `teacher` VALUES ('4', 'peiqi');#7.2、統計各科各分數段人數.顯示格式:課程ID,課程名稱,[100-85],[85-70],[70-60],[ <60]select score.c_id,course.c_name, sum(CASE WHEN num BETWEEN 85 and 100 THEN 1 ELSE 0 END) as '[100-85]',sum(CASE WHEN num BETWEEN 70 and 85 THEN 1 ELSE 0 END) as '[85-70]',sum(CASE WHEN num BETWEEN 60 and 70 THEN 1 ELSE 0 END) as '[70-60]',sum(CASE WHEN num < 60 THEN 1 ELSE 0 END) as '[ <60]' from score,course where score.c_id=course.c_id GROUP BY score.c_id; 復制代碼 需要掌握函數:date_format 復制代碼 --date_format的一些應用: -- 準備表和記錄 create table emp_info(id int primary key auto_increment,name varchar(32),hiredate date);insert into emp_info(name,hiredate) values('sgt','2009-09-02'),('wdc','2010-11-20'),('qxl','2010-11-12'),('ffz','2009-09-18'),('yl','2014-06-16'),('fqy','2014-06-05'),('cnj','2012-04-28'),('bvf','2009-09-18'),('hge','2012-04-22');-- 提取hire_date字段的值,按照格式化后結果年-月來分組。 select date_format(hiredate,'%Y-%m'),count(id) from emp_info GROUP BY date_format(hiredate,'%Y-%m') --結果 -- date_format(hiredate,'%Y-%m') count(id) -- 2009-09 3 -- 2010-11 2 -- 2012-04 2 -- 2014-06 2 -- 按時間分組,統計同一入職時間段的員工人數

六、流程控制

  • 流程控制實際上就是在sql語句中使用if else、while循環(huán)的操作,不同的是語法格式有所不同
# if條件語句 delimiter // CREATE PROCEDURE proc_if () BEGINdeclare i int default 0;if i = 1 THENSELECT 1;ELSEIF i = 2 THENSELECT 2;ELSESELECT 7;END IF;END // delimiter ; # while循環(huán) delimiter // CREATE PROCEDURE proc_while () BEGINDECLARE num INT ;SET num = 0 ;WHILE num < 10 DOSELECTnum ;SET num = num + 1 ;END WHILE ;END // delimiter ;

七、索引和慢查詢優(yōu)化

  • 首先我們要知道索引的存在感,數據庫中的數據最終形式肯定是存在硬盤中,那么我們隊數據庫的操作不可厚非的都會進行IO操作
    既然有IO操作,肯定會存在操作耗時問題,簡單的單個或者多個數據在操作時候我們感覺不出來快慢或者耗時太少,但是現實工作中或者實際的項目的數據庫中的數據可能非常的大,這樣在對數據庫數據操作的IO過程中就會無法忽視IO操作的耗時問題。

  • 由于數據的IO操作導致MySQL的存儲引擎有一套用于快速找到記錄的一種數據結構,這個結構稱之為–索引,在MySQL中也叫‘鍵’

    1:primary key
    2:unique key
    3:index key
    4:注意,我們前面學的外鍵foreign key 不是用來加速查詢的,不算索引,上面的三種key前兩種出了有加速查詢的作用,還有額外的約束條件(primary key:非空且唯一,unique key :唯一),而index 沒有任何約束功能,僅僅具有加速查詢的作用。

  • 所以我們可以總結一下:索引就是一種數據結構,類似于新華字典的最前面那幾頁的查詢方法,按拼音還是按部首可以根據實際情況去選擇,目的只有一個:加速我們找到一個漢字的具體位置,索引就是這樣,也就是說我們在數據庫操作數據應該都是先查找數據,怎么用最快的速度找到數據是個重要的問題,對該數據修改僅僅只算小問題了。

  • 本質:通過不斷縮小我們想要獲取數據的查找范圍,來篩選出最終我們想要的結果,把漫無目的的搜尋變成順理成章的查找,有方法有目的性的去鎖定我們需要的數據。

  • 索引有優(yōu)點肯定也有缺點:

    1:在表中有大量數據的時候,創(chuàng)建索引速度會很慢,同時索引也會占用數據空間
    2:在索引創(chuàng)建完成后,對表的查詢性能會大幅度提升,但是寫的能力會降低

b+樹

  • 上圖,就是b+樹的結構圖,只有最下面的葉子節(jié)點是存放真實數據的,根和樹枝節(jié)點存的僅僅是虛擬的數據
    查詢次數主要由樹的層數決定,也就是說層數越少查找次數越少
    同時一塊磁盤塊的大小也是有限制的,也就是說葉子節(jié)點處的磁盤快存放的數據應該是那種特別小的單位。
    要想降低樹的層級高度,我們應該在一張表中建立一個主鍵id字段,通過該唯一的主鍵字段來鎖定到我們想要的數據。

  • 聚集索引(primary key)
    聚集索引其實指的就是表的主鍵,innodb存儲引擎規(guī)定一張表中必須要有主鍵,在建表時候會在硬盤產生2個文件,一個是表結構frm文件,一個是ibd文件,這里面就存著記錄數據和索引數據。而myisam存儲引擎在建表的時候會在硬盤中產生3個文件,一個表結構frm文件,一個MYD文件存記錄,一個MYI索引文件專門來存索引。

  • 輔助索引(unique,index)
    查詢數據的時候不可能都是用id作為查詢篩選條件,也會用到其他字段名作為查詢條件,name這個時候無法利用到聚集索引來加速查詢,就需要給其他字段建立索引,這些索引就叫做輔助索引。
    特點:葉子節(jié)點存放的是輔助索引字段對應的那條記錄的主鍵的值,比如輔助索引是name這個字段,那么葉子節(jié)點存放的是name這個字段對應的id主鍵值。

-- 覆蓋索引 select name from user where name = 'sgt'; 此語句叫做覆蓋索引 只在輔助索引的葉子節(jié)點中就找到了我們想要的數據記錄-- 非覆蓋索引 select age from user where name = 'sgt'; 此語句叫非覆蓋索引,雖然查詢的時候用的是name索引字段,但是要查詢的是age字段。
  • 以下是了解內容,有興趣可以測試下
  • 索引的測試
#1. 準備表 create table s1( id int, name varchar(20), gender char(6), email varchar(50) );#2. 創(chuàng)建存儲過程,實現批量插入記錄 delimiter $$ #聲明存儲過程的結束符號為$$ create procedure auto_insert1() BEGINdeclare i int default 1;while(i<3000000)doinsert into s1 values(i,'jason','male',concat('jason',i,'@oldboy'));set i=i+1;end while; END$$ #$$結束 delimiter ; #重新聲明 分號為結束符號#3. 查看存儲過程 show create procedure auto_insert1\G #4. 調用存儲過程 call auto_insert1(); # 表沒有任何索引的情況下 select * from s1 where id=30000; # 避免打印帶來的時間損耗 select count(id) from s1 where id = 30000; select count(id) from s1 where id = 1;# 給id做一個主鍵 alter table s1 add primary key(id); # 速度很慢select count(id) from s1 where id = 1; # 速度相較于未建索引之前兩者差著數量級 select count(id) from s1 where name = 'jason' # 速度仍然很慢""" 范圍問題 """ # 并不是加了索引,以后查詢的時候按照這個字段速度就一定快 select count(id) from s1 where id > 1; # 速度相較于id = 1慢了很多 select count(id) from s1 where id >1 and id < 3; select count(id) from s1 where id > 1 and id < 10000; select count(id) from s1 where id != 3;alter table s1 drop primary key; # 刪除主鍵 單獨再來研究name字段 select count(id) from s1 where name = 'jason'; # 又慢了create index idx_name on s1(name); # 給s1表的name字段創(chuàng)建索引 select count(id) from s1 where name = 'jason' # 仍然很慢!!! """ 再來看b+樹的原理,數據需要區(qū)分度比較高,而我們這張表全是jason,根本無法區(qū)分 那這個樹其實就建成了“一根棍子” """ select count(id) from s1 where name = 'xxx'; # 這個會很快,我就是一根棍,第一個不匹配直接不需要再往下走了 select count(id) from s1 where name like 'xxx'; select count(id) from s1 where name like 'xxx%'; select count(id) from s1 where name like '%xxx'; # 慢 最左匹配特性# 區(qū)分度低的字段不能建索引 drop index idx_name on s1;# 給id字段建普通的索引 create index idx_id on s1(id); select count(id) from s1 where id = 3; # 快了 select count(id) from s1 where id*12 = 3; # 慢了 索引的字段一定不要參與計算drop index idx_id on s1; select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx'; # 針對上面這種連續(xù)多個and的操作,mysql會從左到右先找區(qū)分度比較高的索引字段,先將整體范圍降下來再去比較其他條件 create index idx_name on s1(name); select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx'; # 并沒有加速drop index idx_name on s1; # 給name,gender這種區(qū)分度不高的字段加上索引并不難加快查詢速度create index idx_id on s1(id); select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx'; # 快了 先通過id已經講數據快速鎖定成了一條了 select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx'; # 慢了 基于id查出來的數據仍然很多,然后還要去比較其他字段drop index idx_id on s1create index idx_email on s1(email); select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx'; # 快 通過email字段一劍封喉

聯合索引

select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx'; # 如果上述四個字段區(qū)分度都很高,那給誰建都能加速查詢 # 給email加然而不用email字段 select count(id) from s1 where name='jason' and gender = 'male' and id > 3; # 給name加然而不用name字段 select count(id) from s1 where gender = 'male' and id > 3; # 給gender加然而不用gender字段 select count(id) from s1 where id > 3; # 帶來的問題是所有的字段都建了索引然而都沒有用到,還需要花費四次建立的時間 create index idx_all on s1(email,name,gender,id); # 最左匹配原則,區(qū)分度高的往左放 select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx'; # 速度變快

慢查詢日志

設定一個時間檢測所有超出改時間的sql語句,然后針對性的進行優(yōu)化!

總結

以上是生活随笔為你收集整理的MySQL 之视图、 触发器、事务、存储过程、内置函数、流程控制、索引(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。