数据库知识点总结
1.數據庫基礎知識點
1.1數據庫概念
什么是數據庫
簡而言之,就是存儲數據,管理數據的倉庫。
常見的數據庫分為:
關系型數據庫: Oracle、MySQL、SQLServer、Access
非關系型數據庫: MongoDB、Redis、Solr、ElasticSearch、Hive、HBase
1.1.2關系型和非關系型
早期發展的數據庫建立在數據的緊密關系基礎之上(如:父子關系、師生關系),我們稱其為關系型數據庫,也稱為傳統數據庫;現今數據庫建立在數據的松散關系基礎之上(如:中國人和美國人、中國人和印度人、視頻、音頻),我們稱其為非關系型數據庫nosql(not only sql)。業界總在爭論nosql能否干掉傳統數據庫,很多初學者也有這個困惑。以我來看,兩者沒有矛盾,它們各有特點,根據業務情況互補才是真諦。但總的來說原來關系型數據庫一統天下的格局早被打破,領土不斷被蠶食,規模一再的縮小,雖然無法全面被替代,但卻早已風光不在,淪落到一偶之地,Oracle的衰落就是最好的證明,早期只要是全球大企業無一例外都是部署Oracle,但現在都在去Oracle化,阿里就已經全面排斥Oracle。
既然干不掉,很多傳統項目的還是圍繞關系型數據庫的居多,所以我們先來學習關系型數據庫,目前最流行的關系型數據庫是MySQL。
1.1.3關系型數據庫
關系型數據庫有特定的組織方式,其以行和列的形式存儲數據,以便于用戶理解。關系型數據庫這一系列的行和列被稱為表,一組表組成了數據庫。用戶通過查詢來檢索數據庫中的數據,而查詢是一個用于限定數據庫中某些區域的執行代碼。關系模型可以簡單理解為二維表格模型,而一個關系型數據庫就是由二維表及其之間的關系組成的一個數據集合。
1.2Mysql數據庫
Mysql數據庫
(1)mysql服務端,它來處理具體數據維護,保存磁盤
(2)mysql客戶端,CRUD新增,修改,刪除,查詢
1.2.2MySQL數據存放在哪里?
在MySQL的配置文件my.ini中會進行默認配置
1.2.3MySQL服務端
mysql-5.5.27-winx64.msi
Mysql數據庫默認的編碼是latin1等價于iso-8859-1,修改為utf-8
注意:配置完,mysql開始執行,最后一步出錯有時仍可以使用,使用SQLyog工具測試,如不行,再執行安裝程序,選擇remove,刪除,然后重新安裝。同時注意必須是管理員權限。
1.2.4MySQL客戶端1:DOS窗口
mysql -uroot -proot
語法:mysql.exe執行文件
代表參數
-u 用戶名,緊接著寫的
-p 密碼,緊接著寫的
1.2.5MySQL客戶端2:可視化工具
1.3數據庫的結構
數據庫結構
1.4SQL語句
1.4.1定義
結構化查詢語言(Structured Query Language)簡稱SQL(發音:/?es kju? ?el/ “S-Q-L”),是一種特殊目的的編程語言,是一種數據庫查詢和程序設計語言,用于存取數據以及查詢、更新和管理關系數據庫系統;同時也是數據庫腳本文件的擴展名。
SQL 是1986年10 月由美國國家標準局(ANSI)通過的數據庫語言美國標準,接著,國際標準化組織(ISO)頒布了SQL正式國際標準。
1.4.2分類
(1)DML(Data Manipulation Language)數據操縱語言
如:insert,delete,update,select(插入、刪除、修改、檢索)簡稱CRUD操新增Create、查詢Retrieve、修改Update、刪除Delete
(2)DDL(Data Definition Language)數據庫定義語言
如:create table之類
(3)DCL(Data Control Language)數據庫控制語言
如:grant、deny、revoke等,只有管理員才有相應的權限
(4)DQL(Data Query Language)數據庫查詢語言
如: select 語法
注意:SQL不區分大小寫
1.5數據庫常用操作
1.5.1建庫
創建數據庫,數據庫名稱:cgb2022
1.5.2刪庫
刪除名稱是cgb2022的數據庫
1.5.3查看所有數據庫
查看所有數據庫
1.5.4使用數據庫
use cgb2022;1.6表的常用操作
表設計
門店表:** tb_door**
訂單詳情表:** tb_order_detail**
1.6.1創建表
創建tb_door表,有id,door_name,tel字段
1.6.2修改表
添加列
1.6.3刪除表
刪除名稱是tb_door的表
1.6.4查看所有表
查看所有表
1.6.5查看表結構/設計表
查看tb_door表結構
1.7表記錄的常用操作
1.7.1插入記錄
向tb_door表中插入2條記錄
1.7.2查詢記錄
查詢tb_door表中的所有記錄
1.7.3修改記錄
修改tb_door表中id為1的記錄
1.7.4刪除記錄
刪除tb_door表中id為2的數據
1.7.5排序
將tb_door表記錄按照tel排序
1.7.6記錄總數
查詢tb_door表中的總記錄數
1.8數據類型
1.8.1命名規則
(1)字段名必須以字母開頭,盡量不要使用拼音
(2)長度不能超過30個字符(不同數據庫,不同版本會有不同)
(3)不能使用SQL的保留字,如where,order,group
(4)只能使用如下字符az、AZ、0~9、$ 等
(5)racle習慣全大寫:USER_NAME,mysql習慣全小寫:user_name
(6)多個單詞用下劃線隔開,而非java語言的駝峰規則
1.8.2字符
(1)char長度固定,不足使用空格填充,最多容納2000個字符,char(11)存儲abc,占11位。查詢速度極快但浪費空間
(2)varchar變長字符串,最多容納4000個字符,varchar(11)存儲abc,只占3位。查詢稍慢,但節省空間。Oracle為varchar2
(3)大文本: 大量文字(不推薦使用,盡量使用varchar替代)
以utf8編碼計算的話,一個漢字在u8下占3個字節
注:不同數據庫版本長度限制可能會有不同
1.8.3數字
(1)tinyint,int整數類型
(2)float,double小數類型
(3)numeric(5,2) decimal(5,2)—也可以表示小數,表示總共5位,其中可以有兩位小數
(4)decimal和numeric表示精確的整數數字
1.8.4日期
(1)date 包含年月日
(2)time時分秒
(3)datetime包含年月日和時分秒
(4)timestamp時間戳,不是日期,而是從1970年1月1日到指定日期的毫秒數
1.8.5圖片
blob 二進制數據,可以存放圖片、聲音,容量4g。早期有這樣的設計。但其缺點非常明顯,數據庫龐大,備份緩慢,這些內容去備份多份價值不大。同時數據庫遷移時過大,遷移時間過久。所以目前主流都不會直接存儲這樣的數據,而只存儲其訪問路徑,文件則存放在磁盤上。
1.9準備數據
1.9.1部門表 dept
1.9.2員工表 emp
Mysql:
1.10字段約束
1.10.1主鍵約束
**主鍵約束:**如果為一個列添加了主鍵約束,那么這個列就是主鍵,主鍵的特點是唯一且不能為空。通常情況下,每張表都會有主鍵。
添加主鍵約束,例如將id設置為主鍵:
主鍵自增策略當主鍵為數值類型時,為了方便維護,可以設置主鍵自增策略(auto_increment),設置了主鍵自增策略后,數據庫會在表中保存一個AUTO_INCREMENT變量值,初始值為1,當需要id值,不需要我們指定值,由數據庫負責從AUTO_INCREMENT獲取一個id值,作為主鍵值插入到表中。而且每次用完AUTO_INCREMENT值,都會自增1. AUTO_INCREMENT=1
create table abc( id int primary key auto_increment ); insert into abc values(null); insert into abc values(null); insert into abc values(null); select * from abc;1.10.2非空約束
非空約束:如果為一個列添加了非空約束,那么這個列的值就不能為空,但可以重復。
添加非空約束,例如為password添加非空約束:
create table user( id int primary key auto_increment, password varchar(50) not null ); show tables; insert into user values(null,null);//不符合非空約束 insert into user values(null,123;);//OK1.10.3唯一約束
唯一約束:如果為一個列添加了唯一約束,那么這個列的值就必須是唯一的(即不能重復),但可以為空。
添加唯一約束,例如為username添加唯一約束及非空約束:
create table test( id int primary key auto_increment, username varchar(50) unique--唯一約束 ); show tables; insert into test values(null,'lisi'); insert into test values(null,'lisi');--username的值要唯一,重復會報錯的 select * from test;2.數據庫進階
2.1基礎函數
lower
SELECT 'ABC',LOWER('ABC') from dept; --數據轉小寫upper
select upper(dname) from dept --數據轉大寫length
select length(dname) from dept --數據的長度substr
SELECT dname,SUBSTR(dname,1,3) FROM dept; --截取[1,3]concat
select dname,concat(dname,'123') X from dept --拼接數據replace
select dname,replace(dname,'a','666') X from dept --把a字符替換成666ifnull
select ifnull(comm,10) comm from emp #判斷,如果comm是null,用10替換round & ceil & floor
round四舍五入,ceil向上取整,floor向下取整
–直接四舍五入取整
select comm,round(comm) from emp–四舍五入并保留一位小數
select comm,round(comm,1) from emp–ceil向上取整,floor向下取整
select comm,ceil(comm) ,floor(comm) from empuuid
SELECT UUID()
now
select now() -- 年與日 時分秒select curdate() --年與日select curtime() --時分秒year & month & day
–hour()時 minute()分 second()秒
–year()年 month()月 day()日
select now(),year(now()),month(now()),day(now()) from emp ;轉義字符
'作為sql語句符號,內容中出現單撇就會亂套,進行轉義即可
2.2條件查詢
distinct
使用distinct關鍵字,去除重復的記錄行
where
注意:where中不能使用列別名!!
like
通配符%代表0到n個字符,通配符下劃線_代表1個字符
null
select * from emp where mgr is null --過濾字段值為空的select * from emp where mgr is not null --過濾字段值不為空的between and
SELECT * FROM empselect * from emp where sal<3000 and sal>10000select * from emp where sal<=3000 and sal>=10000--等效select * from emp where sal between 3000 and 10000--等效limit
分數最高的記錄:按分數排序后,limit n,返回前n條。Oracle做的很笨,實現繁瑣,后期有介紹,而mysql做的很棒,語法簡潔高效。在mysql中,通過limit進行分頁查詢:
order by
SELECT * FROM emp order by sal #默認升序SELECT * FROM emp order by sal desc #降序2.3統計案例
入職統計
#2015年以前入職的老員工
#2019年以后簽約的員工,日期進行格式轉換后方便比較
SELECT * FROM emp WHERE YEAR(DATE_FORMAT(hiredate,'%Y-%m-%d'))<=2019;#2015年到2019年入職的員工
SELECT * FROM empWHERESTR_TO_DATE(hiredate,'%Y-%m-%d')>='2015-01-01'ANDSTR_TO_DATE(hiredate,'%Y-%m-%d')<='2019-12-31'年薪統計
公司福利不錯13薪,年底雙薪,統計員工的年薪=sal13+comm13
2.4聚合 aggregation
根據一列統計結果
count select count(*) from emp --底層優化了select count(1) from emp --效果和*一樣select count(comm) from emp --慢,只統計非NULL的max / min
select max(sal) from emp --求字段的最大值select max(sal) sal,max(comm) comm from empselect min(sal) min from emp --獲取最小值select min(sal) min,max(sal) max from emp --最小值最大值SELECT ename,MAX(sal) FROM emp group by ename --分組sum / avg
select count(*) from emp --總記錄數select sum(sal) from emp --求和select avg(sal) from emp --平均數2.5分組 group
用于對查詢的結果進行分組統計
group by表示分組, having 子句類似where過濾返回的結果
group by
#每個部門每個崗位的最高薪資和平均薪資,結果中的非聚合列必須出現在分組中,否則業務意義不對
having
#平均工資小于8000的部門
2.6擴展
char和varchar有什么區別?
char為定長字符串,char(n),n最大為255
varchar為不定長字符串,varchar(n),n最大長度為65535
char(10)和varchar(10)存儲abc,那它們有什么差別呢?
char保存10個字符,abc三個,其它會用空格補齊;而varchar只用abc三個位置。
datetime和timestamp有什么區別?
數據庫字段提供對日期類型的支持,是所有數據類型中最麻煩的一個,慢慢使用就會體會出來。
date 是 年與日
time是 時分秒
datetime年月日時分秒,存儲和顯示是一樣的
timestamp時間戳,存儲的不是個日期,而是從1970年1月1日到指定日期的毫秒數
中文亂碼
如果在dos命令下執行insert插入中文數據,數據又亂碼,那現在sqlYog客戶端執行下面命令:
設置客戶端字符集和服務器端相同。如果不知道它到底用的什么編碼?怎么辦呢?很簡單,兩個都嘗試下,哪個最后操作完成,查詢數據庫不亂碼,就用哪個。
那為何會造成亂碼呢?
Mysql數據庫默認字符集是lantin1,也就是以后網頁中遇到的ISO8859-1,它是英文字符集,不支持存放中文。我們創建庫時,可以指定字符集:
create database yhdb charset utf8;但這樣很容易造成服務器和客戶端編碼集不同,如服務器端utf8,客戶端ISO8859-1。mysql和客戶端工具都有習慣的默認編碼設置,好幾個地方,要都統一才可以保證不亂碼。
我們只要保證創建數據庫時用utf8,使用可視化工具一般就基本正確。
注釋
/* 很多注釋內容 */
#行注釋內容
– 行注釋內容,這個使用較多
主鍵、外鍵、唯一索引的區別?
Primary Key 主鍵約束,自動創建唯一索引
Foreign Key 外鍵約束,外鍵字段的內容是引用另一表的字段內容,不能瞎寫
Unique Index 唯一索引,唯一值但不是主鍵
對于約束的好處時,數據庫會進行檢查,違反約束會報錯,操作失敗。數據庫提供了豐富的約束檢查,還有其他約束,但現今弱化關系型數據庫的前提下,基本已經很少使用,記住上面三個即可。
drop、delete和truncate之間的區別?
drop刪除庫或者表,數據和結構定義
delete和truncate只是刪除表的數據
delete可以指定where條件,刪除滿足條件的記錄,tuncate刪除所有記錄
對于自增字段的表,delete不會自增值清零,而truncate是把表記錄和定義都刪除了,然后重建表的定義,所以自增主鍵會重頭開始計數
3.數據庫整合
3.1事務 transaction
什么是事務
數據庫事務(Database Transaction),是指作為單個邏輯工作單元執行的一系列操作,要么完全地執行,要么完全地不執行。
簡單的說:事務就是將一堆的SQL語句(通常是增刪改操作)綁定在一起執行,要么都執行成功,要么都執行失敗,即都執行成功才算成功,否則就會恢復到這堆SQL執行之前的狀態。
下面以銀行轉賬為例,A轉100塊到B的賬戶,這至少需要兩條SQL語句:
給A的賬戶減去100元;
update 賬戶表 set money=money**-100** where name=‘A’;
給B的賬戶加上100元。
update 賬戶表 set money=money**+100** where name=‘B’;
如果在第一條SQL語句執行成功后,在執行第二條SQL語句之前,程序被中斷了(可能是拋出了某個異常,也可能是其他什么原因),那么B的賬戶沒有加上100元,而A卻減去了100元,在現實生活中這肯定是不允許的。
如果在轉賬過程中加入事務,則整個轉賬過程中執行的所有SQL語句會在一個事務中,而事務中的所有操作,要么全都成功,要么全都失敗,不可能存在成功一半的情況。
也就是說給A的賬戶減去100元如果成功了,那么給B的賬戶加上100元的操作也必須是成功的;否則,給A減去100元以及給B加上100元都是失敗的。
事務4個特性ACID
一般來說,事務是必須滿足4個條件(ACID):原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。
原子性:一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中如果發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
一致性:在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及后續數據庫可以自發性地完成預定的工作。
隔離性:數據庫允許多個并發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務并發執行時由于交叉執行而導致數據的不一致。
持久性:事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。
隔離級別
事務隔離分為不同級別,包括
讀未提交(Read uncommitted) 安全性最差,可能發生并發數據問題,性能最好
讀提交(read committed) Oracle默認的隔離級別
可重復讀(repeatable read)MySQL默認的隔離級別,安全性較好,性能一般
串行化(Serializable) 表級鎖,讀寫都加鎖,效率低下,安全性高,不能并發
查詢mysql的隔離級別
在默認情況下,MySQL每執行一條SQL語句,都是一個單獨的事務。如果需要在一個事務中包含多條SQL語句,那么需要手動開啟事務和結束事務。
開啟事務:start transaction;
結束事務:commit(提交事務)或rollback(回滾事務)。
在執行SQL語句之前,先執行start transaction,這就開啟了一個事務(事務的起點),然后可以去執行多條SQL語句,最后要結束事務,commit表示提交,即事務中的多條SQL語句所做出的影響會持久化到數據庫中。或者rollback,表示回滾,即回滾到事務的起點,之前做的所有操作都被撤消了!
SELECT @@tx_isolation;
Repeatable Read(可重讀)
MySQL的默認事務隔離級別,它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行。
事務處理
在 MySQL 中只有使用了 Innodb 數據庫引擎的數據庫或表才支持事務
事務處理可以用來維護數據的完整性,保證成批的 SQL 語句要么全部執行,要么全部不執行
事務用來管理 insert、update、delete 語句,因為這些操作才會“破壞”數據,查詢select語句是不會的
MySQL默認數據庫的事務是開啟的,執行SQL后自動提交。
MySQL的事務也可以改成手動提交,那就有兩個步驟:先開啟,寫完SQL后,再手動提交。
提交 commit
#多條語句時,批量執行,事務提交
#有了事務,多步操作就形成了原子性操作,高并發下也不會引起數據錯亂
#mysql的事務默認就是開啟的 – 多條語句一起操作時,要么一起成功要么一起失敗
BEGIN; #關閉事務的自動提交,相當于start transactionINSERT INTO user (id) VALUES(25);#成功INSERT INTO user (id) VALUES(5);#已經存在5了,會失敗COMMIT; #手動提交事務回滾 rollback
#多條語句,批量執行,insert插入重復的主鍵導致失敗時,事務回滾
BEGIN;INSERT INTO user (id) VALUES(15);INSERT INTO user (id) VALUES(35);#存在了ROLLBACK;#事務回滾,就不會再提交了3.2表強化:6約束 constraints
非空約束 not null
DROP TABLE IF EXISTS tb_user; #如果表存在則刪除,慎用會丟失數據CREATE TABLE tb_user(id INT AUTO_INCREMENT,NAME VARCHAR(30) UNIQUE NOT NULL,age INT,phone VARCHAR(20) UNIQUE NOT NULL,email VARCHAR(30) UNIQUE NOT NULL,PRIMARY KEY (id));DESC tb_user;#id為自增主鍵,null值無效,數據庫會自動用下一個id值替代#age因為運行為null,所以可以設置為nullINSERT INTO tb_user (id,age) VALUES(NULL,NULL);唯一約束 unique
Name字段創建了唯一約束,插入數據時數據庫會進行檢查,如果插入的值相同,就會檢查報錯:
主鍵約束 primary key
主鍵是一條記錄的唯一標識,具有唯一性,不能重復
外鍵約束 foreign key
DROP TABLE IF EXISTS tb_user_address; #如果表存在則刪除,慎用會丟失數據DROP TABLE IF EXISTS tb_user; #如果表存在則刪除,慎用會丟失數據CREATE TABLE tb_user (id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, #自增主鍵NAME VARCHAR(50) NOT NULL UNIQUE, #非空,唯一索引sex CHAR(2) DEFAULT '男', #默認值phone CHAR(18),age INT,CHECK (age>0 AND age<=200),);CREATE TABLE tb_user_address (user_id INT PRIMARY KEY NOT NULL,address VARCHAR(200),foreign key(user_id) REFERENCES tb_user(id));DESC tb_user;tb_user_address中user_id字段錄入tb_user表不存在的主鍵值,將報錯默認約束 default
默認值
DROP TABLE IF EXISTS tb_user; #如果表存在則刪除,慎用會丟失數據CREATE TABLE tb_user (id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, #自增主鍵NAME VARCHAR(50) NOT NULL UNIQUE, #非空,唯一索引sex CHAR(2) DEFAULT '男', #默認值phone CHAR(18),age INT,createdTime DATE DEFAULT NOW());DESC tb_user;檢查約束 check
很少使用,了解即可,錄入age超過200將報錯
3.3表關聯 association
概念
表table代表了生活中一個主體,如部門表dept,員工表emp。表關聯則代表了表之間的關系,如:部門和員工,商品和商品分類,老師和學生,教室和學生。
同時,也要知道,表并不都有關系,它們形成自己的小圈子。如商品和商品詳情一圈,部門和員工一圈,出圈就可能沒關系了,如商品和員工無關,商品和學生無關。
下面我們討論表的關系分為四種:
一對一 one to one QQ和QQ郵箱,員工和員工編號
一對多 one to many 最常見,部門和員工,用戶和訂單
多對一 many to one 一對多反過來,員工和部門,訂單和用戶
多對多 many to many 老師和學生,老師和課程
創建表
表設計特點:
表都以s結束,標識復數
字段多以表的首字母作為開頭,在多表聯查時,方便標識出是哪個表的字段
插入測試數據
INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (108 ,'曾華' ,'男' ,'1977-09-01',95033); INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (105 ,'匡明' ,'男' ,'1975-10-02',95031); INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (107 ,'王麗' ,'女' ,'1976-01-23',95033); INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (101 ,'李軍' ,'男' ,'1976-02-20',95033); INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (109 ,'王芳' ,'女' ,'1975-02-10',95031); INSERT INTO STUDENTS (SNO,SNAME,SSEX,SBIRTHDAY,CLASS) VALUES (103 ,'陸君' ,'男' ,'1974-06-03',95031);INSERT INTO TEACHERS(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (804,'易天','男','1958-12-02','副教授','計算機系'); INSERT INTO TEACHERS(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (856,'王旭','男','1969-03-12','講師','電子工程系'); INSERT INTO TEACHERS(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (825,'李萍','女','1972-05-05','助教','計算機系'); INSERT INTO TEACHERS(TNO,TNAME,TSEX,TBIRTHDAY,PROF,DEPART) VALUES (831,'陳冰','女','1977-08-14','助教','電子工程系');INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('3-105' ,'計算機導論',825); INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('3-245' ,'操作系統' ,804); INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('6-166' ,'模擬電路' ,856); INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('6-106' ,'概率論' ,831); INSERT INTO COURSES(CNO,CNAME,TNO)VALUES ('9-888' ,'高等數學' ,831);INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (103,'3-245',86); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (105,'3-245',75); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (109,'3-245',68); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (103,'3-105',92); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (105,'3-105',88); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (109,'3-105',76); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (101,'3-105',64); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (107,'3-105',91); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (108,'3-105',78); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (101,'6-166',85); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (107,'6-106',79); INSERT INTO SCORES(SNO,CNO,DEGREE)VALUES (108,'6-166',81);3.4多表聯查 join
笛卡爾積 Cartesian product
多表查詢是指基于兩個和兩個以上的表的查詢。在實際應用中,查詢單個表可能不能滿足你的需求,如顯示員工表emp中不只顯示deptno,還要顯示部門名稱,而部門名稱dname在dept表中。
#把兩個表的數據都拼接起來
SELECT * FROM dept,emp上面這種查詢兩個表的方式稱為:笛卡爾積(Cartesian product),又稱直積。一般笛卡爾積沒有實際的業務意義,但多表查詢都是先生成笛卡爾積,再進行數據的篩選過濾。
這點很值得注意,實際開發中盡量少用多表聯查,其根本原因就在這里,查詢過程中,現在內存中構建一個大大的結果集,然后再進行數據的過濾。那這個構建過程,和所使用的內存資源,包括過濾時的判斷,都是既耗費資源,又浪費時間。
這就是阿里規范中禁止3張表以上的聯查的原因:
三種連接 join
內連接 inner join
左(外)連接 left join
右(外)連接 right join
案例:列出research部門下的所有員工的信息
SELECT * FROM empWHERE deptno = ( SELECT deptno FROM dept WHERE dname='research' )案例:怎么用內鏈接 INNER JOIN 實現上面的需求?
SELECT d.dname,e.ename,e.jobFROM emp e INNER JOIN dept dON e.deptno=d.deptnoWHERE d.dname='research'換成left join和right join,看看有什么不同呢?案例:列出tony的擴展信息
SELECT *FROM emp e INNER JOIN empext tON e.empno=t.empnoWHERE e.ename='tony'換成left join和right join,看看有什么不同呢?inner join、left join、right join的區別?
INNER JOIN兩邊都對應有記錄的才展示,其他去掉
LEFT JOIN左邊表中的數據都出現,右邊沒有數據以NULL填充
RIGHT JOIN右邊表中的數據都出現,左邊沒有數據以NULL填充
子查詢 subquery
概念
子查詢是指嵌入在其他select語句中的select語句,也叫嵌套查詢。子查詢執行效率低慎用。記錄少時效率影響不大、圖方便直接使用,記錄多時最好使用其它方式替代。
單行子查詢 =
返回結果為一個
多行子查詢 in
in子查詢
3.5SQL的執行順序
(1) FROM [left_table] 選擇表(2) ON <join_condition> 鏈接條件(3) <join_type> JOIN <right_table> 鏈接(4) WHERE <where_condition> 條件過濾(5) GROUP BY <group_by_list> 分組(6) AGG_FUNC(column or expression),... 聚合(7) HAVING <having_condition> 分組過濾(8) SELECT (9) DISTINCT column,... 選擇字段、去重(9) ORDER BY <order_by_list> 排序(10) LIMIT count OFFSET count; 分頁3.6索引 index
定義
索引是一種排好序的快速查找的數據結構,它幫助數據庫高效的進行數據的檢索。在數據之外,數據庫系統還維護著滿足特定查找算法的數據結構(額外的存儲空間),這些數據結構以某種方式指向數據,這樣就可以在這些數據結構上實現高效的查找算法。這種數據結構就叫做索引。
一般來說索引本身也很大,不可能全部存儲在內存中,因此往往以索引文件的形式存放在磁盤中。目前大多數索引都采用BTree樹方式構建。
分類
單值索引:一個索引只包括一個列,一個表可以有多個列
唯一索引:索引列的值必須唯一,但允許有空值;主鍵會自動創建唯一索引
復合索引:一個索引同時包括多列
創建索引
#查看索引,主鍵會自動創建索引
#創建普通索引
#create index 索引名字 on 表名(字段名); #創建索引create index loc_index on dept(loc); #創建索引創建唯一索引
#創建唯一索引--索引列的值必須唯一 CREATE UNIQUE INDEX 索引名 ON 表名(字段名) CREATE UNIQUE INDEX bindex ON dept(loc)創建復合索引
#如果您希望索引不止一個列,您可以在括號中列出這些列的名稱,用逗號隔開: CREATE INDEX 索引名 ON 表名 (字段1, 字段2) CREATE INDEX PIndex ON Persons (LastName, FirstName)刪除索引
alter table dept drop index fuhe_index索引掃描類型
type:
ALL 全表掃描,沒有優化,最慢的方式
index 索引全掃描,其次慢的方式
range 索引范圍掃描,常用語<,<=,>=,between等操作
ref 使用非唯一索引掃描或唯一索引前綴掃描,返回單條記錄,常出現在關聯查詢中
eq_ref 類似ref,區別在于使用的是唯一索引,使用主鍵的關聯查詢
const/system 單條記錄,系統會把匹配行中的其他列作為常數處理,如主鍵或唯一索引查詢,system是const的特殊情況
null MySQL不訪問任何表或索引,直接返回結果
最左特性
explainselect * from dept where loc='二區' #使用了loc索引explainselect * from dept where dname='研發部'#使用了dname索引explainselect * from dept where dname='研發部' and loc='二區' #使用了dname索引當我們創建一個聯合索引(復合索引)的時候,如(k1,k2,k3),相當于創建了(k1)、(k1,k2)、(k1,k3)和(k1,k2,k3)索引,這就是最左匹配原則,也稱為最左特性。
為何索引快?
明顯查詢索引表比直接查詢數據表要快的多,首先,索引表是排序了,可以類似二分查找,非常有效的提高了查詢的速度。
其過程如下圖,先到事先排序好的索引表中檢索查詢,找到其主鍵后,就直接定位到記錄所在位置,然后直接返回這條數據。
排序,tree結構,類似二分查找
索引表小
小結
優點:
索引是數據庫優化
表的主鍵會默認自動創建索引
每個字段都可以被索引
大量降低數據庫的IO磁盤讀寫成本,極大提高了檢索速度
索引事先對數據進行了排序,大大提高了查詢效率
缺點:
索引本身也是一張表,該表保存了主鍵與索引字段,并指向實體表的記錄,所以索引列也要占用空間
索引表中的內容,在業務表中都有,數據是重復的,空間是“浪費的”
雖然索引大大提高了查詢的速度,但對數據的增、刪、改的操作需要更新索引表信息,如果數據量非常巨大,更新效率就很慢,因為更新表時,MySQL不僅要保存數據,也要保存一下索引文件
隨著業務的不斷變化,之前建立的索引可能不能滿足查詢需求,需要消耗我們的時間去更新索引
3.7視圖View
概念
可視化的表,視圖當做是一個特殊的表,是指,把sql執行的結果,直接緩存到了視圖中。
下次還要發起相同的sql,直接查視圖。現在用的少,了解即可.
使用: 1,創建視圖 2,使用視圖
測試
create view 視圖名 as SQL語句; select * from 視圖名; #視圖:就是一個特殊的表,緩存上次的查詢結果 #好處是提高了SQL的復用率,壞處是占內存無法被優化#1.創建視圖 CREATE VIEW emp_view AS SELECT * FROM emp WHERE ename LIKE '%a%' #模糊查詢,名字里包含a的 #2.使用視圖 SELECT * FROM emp_view3.8SQL優化
創建mysql-db庫
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mysql-db` /*!40100 DEFAULT CHARACTER SET utf8 */;USE `mysql-db`;準備student表
DROP TABLE IF EXISTS `student`;CREATE TABLE `student` (`id` varchar(4) NOT NULL,`NAME` varchar(20) DEFAULT NULL,`sex` char(2) DEFAULT NULL,`birthday` date DEFAULT NULL,`salary` decimal(7,2) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;insert into `student`(`id`,`NAME`,`sex`,`birthday`,`salary`) values ('1','張慎政','男','2020-01-01','10000.00'),('2','劉沛霞','女','2020-01-02','10000.00'),('3','劉昱江','男','2020-01-03','10000.00'),('4','齊雷','男','2020-01-04','20000.00'),('5','王海濤','男','2020-01-05','20000.00'),('6','董長春','男','2020-01-06','10000.00'),('7','張久軍','男','2020-01-07','20000.00'),('8','陳子樞','男','2020-10-11','3000.00');準備tb_dept表
DROP TABLE IF EXISTS `tb_dept`;CREATE TABLE `tb_dept` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(50) DEFAULT NULL,`parent_id` int(11) DEFAULT NULL,`sort` int(11) DEFAULT NULL,`note` varchar(100) DEFAULT NULL,`created` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),`updated` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;insert into `tb_dept`(`id`,`name`,`parent_id`,`sort`,`note`,`created`,`updated`) values (1,'集團',0,1,'集團總部','2018-10-02 09:15:14','2018-09-27 16:35:54'),(2,'財務部',1,2,'財務管理','2018-09-27 16:35:52','2018-09-27 16:34:15'),(3,'軟件部',1,3,'開發軟件、運維','2018-09-27 16:35:54','2018-09-27 16:34:51');準備tb_user表
DROP TABLE IF EXISTS `tb_user`;CREATE TABLE `tb_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`dept_id` int(11) DEFAULT NULL,`username` varchar(50) DEFAULT NULL,`password` varchar(100) DEFAULT NULL,`salt` varchar(50) DEFAULT NULL,`email` varchar(100) DEFAULT NULL,`mobile` varchar(100) DEFAULT NULL,`valid` tinyint(4) DEFAULT NULL,`created` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),`updated` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;insert into `tb_user`(`id`,`dept_id`,`username`,`password`,`salt`,`email`,`mobile`,`valid`,`created`,`updated`) values (1,1,'陳集團','123456',NULL,'tony@sina.com','13572801415',1,'2018-09-30 09:32:18','2018-09-30 09:32:18'),(2,3,'牛軟件','567890',NULL,'niu@sina.com','13208737172',0,'2018-10-02 09:23:19','2018-09-20 09:32:18');*查詢SQL盡量不要使用select ,而是具體字段
反例:SELECT * FROM student正例:SELECT id,NAME FROM student理由:字段多時,大表能達到100多個字段甚至達200多個字段 只取需要的字段,節省資源、減少網絡開銷 select * 進行查詢時,很可能不會用到索引,就會造成全表掃描避免在where子句中使用or來連接條件
反例:SELECT * FROM student WHERE id=1 OR salary=30000正例:#分開兩條sql寫SELECT * FROM student WHERE id=1SELECT * FROM student WHERE salary=30000理由:使用or可能會使索引失效,從而全表掃描 對于or沒有索引的salary這種情況,假設它走了id的索引,但是走到salary查詢條件時,它還得全表掃描。也就是說整個過程需要三步:全表掃描+索引掃描+合并。如果它一開始就走全表掃描,直接一遍掃描就搞定。雖然mysql是有優化器的,處于效率與成本考慮,遇到or條件,索引還是可能失效的使用varchar代替char
反例:`deptname` char(100) DEFAULT NULL COMMENT '部門名稱'正例:`deptname` varchar(100) DEFAULT NULL COMMENT '部門名稱'理由:varchar變長字段按數據內容實際長度存儲,存儲空間小,可以節省存儲空間 char按聲明大小存儲,不足補空格 其次對于查詢來說,在一個相對較小的字段內搜索,效率更高盡量使用數值替代字符串類型
主鍵(id):primary key優先使用數值類型int,tinyint 性別(sex):0-代表女,1-代表男;數據庫沒有布爾類型,mysql推薦使用tinyint 支付方式(payment):1-現金、2-微信、3-支付寶、4-信用卡、5-銀行卡 服務狀態(state):1-開啟、2-暫停、3-停止 商品狀態(state):1-上架、2-下架、3-刪除查詢盡量避免返回大量數據
如果查詢返回數據量很大,就會造成查詢時間過長,網絡傳輸時間過長。同時,大量數據返回也可能沒有實際意義。如返回上千條甚至更多,用戶也看不過來。
通常采用分頁,一頁習慣10/20/50/100條。
使用explain分析你SQL執行計劃
SQL很靈活,一個需求可以很多實現,那哪個最優呢?SQL提供了explain關鍵字,它可以分析你的SQL執行計劃,看它是否最佳。Explain主要看SQL是否使用了索引。
是否使用了索引及其掃描類型
type:
ALL 全表掃描,沒有優化,最慢的方式
index 索引全掃描
range 索引范圍掃描,常用語<,<=,>=,between等操作
ref 使用非唯一索引掃描或唯一索引前綴掃描,返回單條記錄,常出現在關聯查詢中
eq_ref 類似ref,區別在于使用的是唯一索引,使用主鍵的關聯查詢
const/system 單條記錄,系統會把匹配行中的其他列作為常數處理,如主鍵或唯一索引查詢
null MySQL不訪問任何表或索引,直接返回結果
key:
真正使用的索引方式
創建name字段的索引
優化like語句
模糊查詢,程序員最喜歡的就是使用like,但是like很可能讓你的索引失效
反例:
EXPLAINSELECT id,NAME FROM student WHERE NAME LIKE '%1'EXPLAINSELECT id,NAME FROM student WHERE NAME LIKE '%1%'正例:
EXPLAINSELECT id,NAME FROM student WHERE NAME LIKE '1%'字符串怪現象
反例:
正例:
#使用索引EXPLAINSELECT * FROM student WHERE NAME='123'理由:
為什么第一條語句未加單引號就不走索引了呢?這是因為不加單引號時,是字符串跟數字的比較,它們類型不匹配,MySQL會做隱式的類型轉換,把它們轉換為數值類型再做比較
索引不宜太多,一般5個以內
索引并不是越多越好,雖其提高了查詢的效率,但卻會降低插入和更新的效率
索引可以理解為一個就是一張表,其可以存儲數據,其數據就要占空間
再者,索引表的一個特點,其數據是排序的,那排序要不要花時間呢?肯定要
insert或update時有可能會重建索引,如果數據量巨大,重建將進行記錄的重新排序,所以建索引需要慎重考慮,視具體情況來定
一個表的索引數最好不要超過5個,若太多需要考慮一些索引是否有存在的必要
索引不適合建在有大量重復數據的字段上
如性別字段。因為SQL優化器是根據表中數據量來進行查詢優化的,如果索引列有大量重復數據,Mysql查詢優化器推算發現不走索引的成本更低,很可能就放棄索引了。
where限定查詢的數據
數據中假定就一個男的記錄
反例:
SELECT id,NAME FROM student WHERE sex='男'正例:
SELECT id,NAME FROM student WHERE id=1 AND sex='男'理由:
需要什么數據,就去查什么數據,避免返回不必要的數據,節省開銷
避免在where中對字段進行表達式操作
反例:
正例:
EXPLAINSELECT * FROM student WHERE id=+1-1+1EXPLAINSELECT * FROM student WHERE id=1理由:
SQL解析時,如果字段相關的是表達式就進行全表掃描
避免在where子句中使用!=或<>操作符
應盡量避免在where子句中使用!=或<>操作符,否則引擎將放棄使用索引而進行全表掃描。記住實現業務優先,實在沒辦法,就只能使用,并不是不能使用。如果不能使用,SQL也就無需支持了。
反例:
EXPLAINSELECT * FROM student WHERE salary!=3000EXPLAINSELECT * FROM student WHERE salary<>3000理由:
使用!=和<>很可能會讓索引失效
去重distinct過濾字段要少
索引失效
EXPLAINSELECT DISTINCT * FROM student索引生效
EXPLAINSELECT DISTINCT id,NAME FROM studentEXPLAINSELECT DISTINCT NAME FROM student理由:
帶distinct的語句占用cpu時間高于不帶distinct的語句。因為當查詢很多字段時,如果使用distinct,數據庫引擎就會對數據進行比較,過濾掉重復數據,然而這個比較、過濾的過程會占用系統資源,如cpu時間
where中使用默認值代替null
#修改表,增加age字段,類型int,非空,默認值0
批量插入性能提升
大量數據提交,上千,上萬,批量性能非常快,mysql獨有
多條提交:
INSERT INTO student (id,NAME) VALUES(4,'齊雷');INSERT INTO student (id,NAME) VALUES(5,'劉昱江');批量提交:
INSERT INTO student (id,NAME) VALUES(4,'齊雷'),(5,'劉昱江');理由:
默認新增SQL有事務控制,導致每條都需要事務開啟和事務提交;而批量處理是一次事務開啟和提交。自然速度飛升
數據量小體現不出來
批量刪除優化
避免同時修改或刪除過多數據,因為會造成cpu利用率過高,會造成鎖表操作,從而影響別人對數據庫的訪問。
反例:
#一次刪除10萬或者100萬+?
delete from student where id <100000;采用單一循環操作,效率低,時間漫長
for(User user:list){delete from student;}正例:
//分批進行刪除,如每次500
for(){delete student where id<500;}delete student where id>=500 and id<1000;理由:
一次性刪除太多數據,可能造成鎖表,會有lock wait timeout exceed的錯誤,所以建議分批操作
偽刪除設計
商品狀態(state):1-上架、2-下架、3-刪除
理由:
這里的刪除只是一個標識,并沒有從數據庫表中真正刪除,可以作為歷史記錄備查
同時,一個大型系統中,表關系是非常復雜的,如電商系統中,商品作廢了,但如果直接刪除商品,其它商品詳情,物流信息中可能都有其引用。
通過where state=1或者where state=2過濾掉數據,這樣偽刪除的數據用戶就看不到了,從而不影響用戶的使用
操作速度快,特別數據量很大情況下
提高group by語句的效率
可以在執行到該語句前,把不需要的記錄過濾掉
反例:先分組,再過濾
select job,avg(salary) from employee group by job having job ='president' or job = 'managent';正例:先過濾,后分組
select job,avg(salary) from employee where job ='president' or job = 'managent' group by job;復合索引最左特性
創建復合索引,也就是多個字段
滿足復合索引的左側順序,哪怕只是部分,復合索引生效
EXPLAINSELECT * FROM student WHERE NAME='陳子樞'沒有出現左邊的字段,則不滿足最左特性,索引失效
EXPLAINSELECT * FROM student WHERE salary=3000復合索引全使用,按左側順序出現 name,salary,索引生效
EXPLAINSELECT * FROM student WHERE NAME='陳子樞' AND salary=3000雖然違背了最左特性,但MYSQL執行SQL時會進行優化,底層進行顛倒優化
EXPLAINSELECT * FROM student WHERE salary=3000 AND NAME='陳子樞'理由:
復合索引也稱為聯合索引
當我們創建一個聯合索引的時候,如(k1,k2,k3),相當于創建了(k1)、(k1,k2)和(k1,k2,k3)三個索引,這就是最左匹配原則
聯合索引不滿足最左原則,索引一般會失效,但是這個還跟Mysql優化器有關的
排序字段創建索引
什么樣的字段才需要創建索引呢?原則就是where和order by中常出現的字段就創建索引。
#使用 *,包含了未索引的字段,導致索引失效
EXPLAINSELECT * FROM student ORDER BY NAME;#name字段有索引
EXPLAINSELECT id,NAME FROM student ORDER BY NAME#排序字段未創建索引,性能就慢
EXPLAINSELECT id,NAME FROM student ORDER BY sex刪除冗余和重復的索引
SHOW INDEX FROM student#創建索引index_name
ALTER TABLE student ADD INDEX index_name (NAME)#刪除student表的index_name索引
DROP INDEX index_name ON student ;#修改表結果,刪除student表的index_name索引
ALTER TABLE student DROP INDEX index_name ;#主鍵會自動創建索引,刪除主鍵索引
ALTER TABLE student DROP PRIMARY KEY ;不要有超過5個以上的表連接
關聯的表個數越多,編譯的時間和開銷也就越大
每次關聯內存中都生成一個臨時表
應該把連接表拆開成較小的幾個執行,可讀性更高
如果一定需要連接很多表才能得到數據,那么意味著這是個糟糕的設計了
阿里規范中,建議多表聯查三張表以下
inner join 、left join、right join,優先使用inner join
三種連接如果結果相同,優先使用inner join,如果使用left join左邊表盡量小
inner join 內連接,只保留兩張表中完全匹配的結果集
left join會返回左表所有的行,即使在右表中沒有匹配的記錄
right join會返回右表所有的行,即使在左表中沒有匹配的記錄
理由:
如果inner join是等值連接,返回的行數比較少,所以性能相對會好一點
同理,使用了左連接,左邊表數據結果盡量小,條件盡量放到左邊處理,意味著返回的行數可能比較少。這是mysql優化原則,就是小表驅動大表,小的數據集驅動大的數據集,從而讓性能更優
in子查詢的優化
日常開發實現業務需求可以有兩種方式實現:
一種使用數據庫SQL腳本實現
一種使用程序實現
如需求:查詢所有部門的所有員工:
#in子查詢
SELECT * FROM tb_user WHERE dept_id IN (SELECT id FROM tb_dept);#這樣寫等價于:
#先查詢部門表
SELECT id FROM tb_dept#再由部門dept_id,查詢tb_user的員工
SELECT * FROM tb_user u,tb_dept d WHERE u.dept_id = d.id假設表A表示某企業的員工表,表B表示部門表,查詢所有部門的所有員工,很容易有以下程序實現,可以抽象成這樣的一個嵌套循環:
List<> resultSet;for(int i=0;i<B.length;i++) {for(int j=0;j<A.length;j++) {if(A[i].id==B[j].id) {resultSet.add(A[i]);break;}}}上面的需求使用SQL就遠不如程序實現,特別當數據量巨大時。
理由:
數據庫最費勁的就是程序鏈接的釋放。假設鏈接了兩次,每次做上百萬次的數據集查詢,查完就結束,這樣就只做了兩次;相反建立了上百萬次鏈接,申請鏈接釋放反復重復,就會額外花費很多實際,這樣系統就受不了了,慢,卡頓
3.9數據庫設計的三范式
概述
簡言之就是,數據庫設計對數據的存儲性能,還有開發人員對數據的操作都有莫大的關系。所以建立科學的,規范的的數據庫是需要滿足一些規范的來優化數據數據存儲方式。在關系型數據庫中這些規范就可以稱為范式,也是作為數據庫 設計的一些規則.
關系型數據庫有六種范式:
第一范式(1NF)、
第二范式(2NF)、
第三范式(3NF)、巴斯-科德范式(BCNF)
第四范式(4NF)
第五范式(5NF,又稱完美范式)。
范式越高,冗余最低,一般到三范式,再往上,表越多,可能導致查詢效率下降。所以有時為了提高運行效率,可以讓數據冗余.
1NF的定義為:符合1NF的關系中的每個屬性都不可再分
2NF在1NF的基礎之上,消除了非主屬性對于碼的部分函數依賴,也就是說,表里的每個字段都要依賴于主鍵
第一步:找出數據表中所有的碼。
第二步:根據第一步所得到的碼,找出所有的主屬性。
第三步:數據表中,除去所有的主屬性,剩下的就都是非主屬性了。
第四步:查看是否存在非主屬性對碼的部分函數依賴
3NF在2NF的基礎之上,消除了非主屬性對于碼的傳遞函數依賴
就是指沒個屬性都跟主鍵有直接關系而不是間接關系。
像:a–>b–>c 屬性之間含有這樣的關系,是不符合第三范式的。
比如Student表(學號,姓名,年齡,性別,所在院校,院校地址,院校電話)
這樣一個表結構,就存在上述關系。 學號–> 所在院校 --> (院校地址,院校電話)
這樣的表結構,我們應該拆開來,如下。
(學號,姓名,年齡,性別,所在院校)–(所在院校,院校地址,院校電話)
總結
三大范式只是一般設計數據庫的基本理念,可以建立冗余較小、結構合理的數據庫。如果有特殊情況,當然要特殊對待,數據庫設計最重要的是看需求跟性能,需求>性能>表結構。所以不能一味的去追求范式建立數據庫。
3.10SQL面試題
查詢所有記錄 select * from emp只查詢指定列 SELECT id,ename,sal from emp查詢id為100的記錄 select * from emp where id=100模糊查詢記錄 select * from emp where ename like 'j%' #以j開頭的記錄select * from emp where ename like '%k' #以k結束的記錄select * from emp where ename like '%a%' #包含a的記錄select * from emp where ename not like 'j%' #不 以j開頭的記錄查詢之間范圍之間的所有記錄 select * from emp where sal between 8000 and 20000 #[8000,20000]select * from emp where sal>8000 and sal<20000 #(8000,20000)查詢滿足兩個條件的記錄 SELECT * from user where age=19 or age=20 #或者關系SELECT * from user where age in (19,20)SELECT * from user where age=20 and name='xiongda' #并且關系查詢用戶住址 SELECT distinct addr from user查詢19歲人的名字 SELECT distinct name from user where age=19按age升序查詢記錄 SELECT * from user order by age asc #升序,默認SELECT * from user order by age desc #降序以name升序、age降序查詢記錄 SELECT * from user order by name asc,age desc #name升序,age降序查詢總人數 SELECT count(*) from userSELECT count(1) from userSELECT count(id) from user查詢各個城市的人數 select addr,count(addr) from user group by addr #聚合函數以外的列要分組查詢至少有2人的地址 SELECT addr,count(name) from user GROUP BY addrSELECT addr,count(name) X from user GROUP BY addr having X>2 #條件過濾查詢記錄中最年長和最年輕 select max(age),min(age) from user查詢大于平均年齡的記錄 select * from user where age > (select avg(age) from user)查詢年齡最大的用戶信息 select * from user where age = (select max(age) from user)查詢各部門的最高薪 select id,name,sal,max(sal) from emp GROUP BY deptno查詢各科的平均工資 select avg(comm) from empselect ROUND(avg(comm),1) from emp #保留一位小數SELECT * from emp where comm > (select avg(comm) from emp)查詢id是100或200的記錄 select * from emp where id=100select * from emp where id=200select * from emp where id=100 or id=200select * from emp where id in(100,200)select * from emp where id=200#UNION #合并重復內容union all #不合并重復內容select * from emp where id=200查詢存在部門的員工信息 select * from emp where deptno in (select id from dept)查詢沒劃分部門的員工信息 select * from emp where deptno not in(select id from dept)查詢同名的員工記錄 select * from emp WHERE ename in (select ename from emp GROUP BY ename HAVING count(ename)>1)全部學生按出生年月排行 select * from students order by sbirthday #數值從小到大,年齡就是大到小了每個班上最小年齡的學員 select sname,class,max(sbirthday) from students group by class #數字最大,年齡是最小的查詢學生的姓名和年齡 select sname,year(now())-year(sbirthday) age from students查詢男教師及其所上的課程 SELECT * from teachers a inner JOIN courses b on a.tno=b.tno AND a.tsex='男'SELECT * from teachers a,courses b where a.tno=b.tno AND a.tsex='男'查詢每個老師教的課程 SELECT c.cname,t.tname,t.prof,t.departFROM teachers tLEFT JOIN courses c ON t.tno = c.tno查詢女老師的信息 SELECT *FROM teachers tLEFT JOIN courses c ON t.tno = c.tnowhere t.tsex='女' 第一種先連接數據后過濾數據,假如數據量很大,第一種中間過程要構建巨大的臨時表。而第二種方式先過濾數據,構建的中間結果集自然就變的很小。所占內存,所加工的時間所網絡傳輸的時間都變少了,所以效率高。查詢得分前3名的學員信息 select * from scores order by degree desc limit 3 #前三條select * from scores order by degree desc limit 1,3#從1位置(第二條)開始,總共取3條查詢課程是“計算機導論”的,得分前3名的學員信息 select * from scores where cno = (select cno from courses where cname='計算機導論')order by degree desc limit 3課程號“3-105”的倒數最后3名學員排行 select * from scores where cno='3-105' order by degree limit 3筆記補充:
1、create database cgb210801 default character set utf8; #指定字符集,避免了中文亂碼
2、表里有幾個字段values需要提供幾個值+值的順序和字段順序一致
3、主鍵約束,給字段添加PRIMARY KEY ,特點是:字段值必須唯一 + 值不能為null,
主鍵自增策略:是指主鍵的值不需要程序員數,
交給數據庫自增,給主鍵添加 AUTO_INCREMENT
4、查詢多個字段的值時用逗號隔開
5、like模糊查詢 %是通配符,通配0~n個字符
6、漢字排序時會查utf8里對應的數字,按照數字升序排序
7、按照什么分組?按照非聚合列分組
8、什么時候要分組?查詢時出現了混合列
9、group by后的過濾必須用having
10、where里不能用別名,不能出現聚合函數,比having高效
11、having和where能互換嗎?效率誰高? 可以,但如果有別名或者值聚合函數就不能互換,where的效率比having高
12、檢查約束:給字段使用check添加合法性的檢查
14、外鍵foreign key的作用:
通過兩張表的主鍵來約束兩張表,防止了冗余的數據,并通過外鍵來描述兩張表的關系
外鍵約束:給字段添加外鍵約束
特點:給子表中的主鍵的值添加數據時,子表的主鍵值 必須 取自主表
當主表刪除數據時,子表沒有相關的記錄,子表不在占用主表資源
創建外鍵的語法:foreign key(本表的主鍵名) references 對方的表名(對方的主鍵)
15、索引的使用步驟:創建索引(索引創建原則:經常按照指定字段查詢)+使用索引
16、索引的操作可以增刪改查
17、主鍵自帶索引,提高查詢效率
18、explain關鍵字:查詢SQL的執行計劃/性能(看看用沒用索引)和sql一起執行,用來查看在查詢中有沒有用索引,possible_keys用到的索引
19、創建索引的時候一般把表設計好以后就創建了,因為在填充數據以后再來添加索引的話,比如像唯一索引有時候就不太方便了
21、字段里面的信息如果有重復的話,不能創建唯一索引
21、復合索引可能會存在一種特殊情況,復合索引失效,查詢要滿足最左特性【A,B,C】不管怎么查多要包括字段A,
另外比如查詢(C,A)也不會影響
不按照最左特性來查詢的話,最壞的結果也就是查詢的慢一些,像是不加索引一樣
優勢:簡化了一個一個創建索引的方式,多個列同時使用一個復合索引
22、索引:好處是:提高查詢效率 壞處是:索引需要單獨的一張表
23、創建單值索引:一個索引只包含一個字段
24、視圖:
語法:create view 視圖名 as 查詢的SQL語句
(1)創建唯一索引:一個索引只包 含一個字段,索引列值不能重復、
(2)視圖查詢的優勢感受比索引更直觀,但前提是把SQL寫出來,然后不執行結果存在視圖中
(3)視圖的增刪改效率很低,所以視圖通常用來查詢
(4)和索引一樣,都是對數據庫優化的有效方案.
(5)特點:
1, 可以把視圖當做表來使用
2,視圖里存的數據是 SQL查詢到的結果
3,SQL無法優化,要合理的使用視圖
(6)好處和壞處:
好處是:
1.簡化了查詢的SQL(相同的SQL需求不必再寫SQL了,直接查視圖)
2.視圖可以被共享,視圖屏蔽了真實業務表的復雜性
壞處是:視圖一旦創建,SQL無法被優化
26、多表聯查三種方式
1, 笛卡爾積: 語法 select * from 表名1,表名2,表名3 , 笛卡爾積,通過逗號連接表名 (1)SELECT * FROM dept,emp #表名.字段名=表名.字段名 WHERE dept.deptno=emp.deptno#描述兩個表的關系 AND dept.deptno=1#查deptno=1的數據 (2) (3) (4) (5) 2, 連接查詢 內連接inner join:取兩張表的交集 左連接left join:取左表的所有和右表滿足條件的 右連接right join:取右表的所有和左表滿足條件的 (1)inner join=join(可以簡寫) (2)取左表的所有,右邊滿足條件的取到不滿足條件的用null填充 (3)取右表的所有,左邊滿足條件的取到不滿足條件的用null填充 (4) (5) 3, 子查詢 查詢/嵌套查詢:把上次的查詢結果作為這次的查詢條件 SELECT SUM(degree) FROM scores WHERE sno=(SELECT sno FROM students WHERE sname='李軍')(1)多表聯查禁止3張以上總結
- 上一篇: iOS商户进件之【营业执照编号校验】18
- 下一篇: linux cmake编译源码,linu