03、Mysql 索引及高級數據操作


索引及高級數據操作

一、  索引

1、       索引的概念:系統根據已有的數據(未來可能新增的數據),單獨建立一個文件:文件能夠實現快速的匹配數據,並且能夠快速的找到表中的對應數據

2、       索引的意義:

1)      提升查詢數據的效率

2)      約束數據的有效性(唯一性等等)

3、       前提:

1)索引會產生索引文件,有時候會比數據文件大,這樣會非常耗費磁盤空間。我們就需要再效率和磁盤空間之間找出一個平衡。如果某個字段作爲查詢的條件,那麼我們就一定會使用索引(而且會想辦法去增加索引)

2)如果某個字段需要進行數據的有效性的約束,那麼我們也可以使用索引(主鍵,唯一鍵)。

 

l 注意:mysql中提供了多種索引:

1)      主鍵索引:primary key,就是我們之前講的主鍵

2)      唯一索引:unique key,就是我們之前講過的唯一鍵

3)      全文索引:fulltext index

針對文章內部的關鍵字進行索引,全文最大的一個問題就是如何去確定關鍵字。如果是英文的話就會比較容易,英文單詞之間是有空格的。中文的話,沒有空格,而且中文是可以隨意組合的(分詞:sphinx)。

4)      普通索引:index

 

二、 關係

將實體與實體之間的關係,反應到最終的數據庫表的設計上來,我們可以將關係分爲:一對一、一對多(多對一)、多對多。所有的關係都指的是表和表之間的關係

 

1、      一對一的關係

一張表的一條記錄只能與另外一張表中的一條記錄進行對應,反之亦然

學生表:姓名、性別、年齡、身高、體重、婚姻狀況、籍貫、家庭住址、緊急聯繫人等

Id

姓名

年齡

體重

身高

婚姻

籍貫

住址

聯繫人

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

問題:表的設計成以上這種形式:符合要求,其中姓名,性別,年齡,身高,體重屬於常用數據,其他的都是不常用數據,如果每次查詢所有的數據,不常用的數據就會影響效率,實際上不是很實用。

解決方案:將常用的信息分別存儲,分成兩張表:

   常用表

Id

姓名

年齡

體重

身高

性別

 

 

 

 

 

 

 

 

 

 

 

 

   不常用表:

Id

婚姻

籍貫

住址

聯繫人

 

 

 

 

 

 

 

 

 

 

           注意:一個常用表中的一條記錄,永遠只能在一張不常用的表中找到一條與之對應的記錄;反之亦然。這就是一對一的關係的實際應用。

2、      一對多的關係

概念:一張表中有一條記錄 可以對應另外一張表中的多條記錄,這種就是一對多的關係或者是多對一的關係。

媽媽表:

Id

姓名

年齡

性別

 

 

 

 

孩子表

Id

姓名

年齡

性別

 

 

 

 

問題:這樣設計的表解決了表的實體設計問題,但是沒有解決關係問題。孩子找不到媽媽,媽媽也找不到孩子。

 

解決方案:在某一張表中,增加一個字段,使其能夠找到其中對應的記錄:那麼我們應該在孩子表中增加一個字段使其指向媽媽。因爲孩子只能也只需要匹配一條媽媽的記錄。

 

孩子表:

Id

姓名

性別

年齡

母親Id

 

 

 

 

 

這個指向媽媽表的主鍵。

3、      多對多關係

概念:一張表(A)的一條記錄能夠對應另外一張表(B)中的多條記錄,反之亦然。

這種關係被廣泛應用於商品和訂單之間的關係

簡單實例:老師與學生的關係

老師表

Teacher_id

姓名

性別

1

A

2

B

學生表

Student_id

姓名

性別

1

張三

2

李四

問題:這樣子的設計方案:體現了實體的設計,但是沒有維護實體的關係,一個老師教過很多的學生,一個學生也被很多的老師教過

解決方案:在學生表中增加老師字段並且在老師表中增加學生字段,但是這樣的設計也會出現另外一個問題,就是增加的該字段要保存多條數據,而且是與其他表有關係的字段,這樣是不符合設計規範,我們就應該增加一張新表,專門維護兩張表之間的關係。

 

Teacher_id

Student_id

 

1

1

 

1

2

 

2

2

 

2

1

增加了中間表之後,中間表就與老師表形成了一對多的關係,而且中間表是多表。維護了能夠唯一找到一表的關係;同樣的學生表也與中間表形成了一對多的關係

 

方案:

學生找老師,找出學生ID(一條)-> 中間表尋找匹配記錄(多條)->老師匹配表(一條)

老師找學生,找出老師ID(一條)-> 中間表尋找匹配記錄(多條)->學生匹配表(一條)

三、   範式

1、       概述:

範式(NomalFormat),是一種離散數學之中的知識,是爲了解決數據存儲於優化的問題,保存數據之後,凡是能夠通過關係尋找出來的數:終極目標是爲了減少數據的冗餘。他是一種分層結構的規範,分爲六層:每一層都比上層更加嚴格:若要滿足下一層範式,前提是滿足上一層範式

 

六層範式:1NF,2NF,3NF,4NF,5NF,6NF;INF是最底層要求最低,6NF是最高層,最嚴格。

 

Mysql屬於關係型數據:有空間的浪費,也是致力於節省空間,與範式要解決的問題不謀而合,在設計數據庫的時候,我們會利用範式來指導設計。但是數據庫不單是要解決空間問題,又要保證效率。範式只是爲了解決空間問題,所以數據庫的設計與不可能完全按照範式的要求實現:一般情況下,只有前三層範式需要滿足。我們只要滿足到3NF就可以了。所以說,範式在數據庫的設計當中是有指導意義,單是不是強制的規範。

 

2、      1NF

第一範式:在設計表存儲數據的時候,如果表中設計的字段存儲的數據,在取出來使用之前還需要進行額外的處理(拆分),那麼說明表的設計不滿足第一範式:第一範式要求字段的數據具有原子性,不可再分。

問題:上表的設計沒有問題,但是如果需要將數據查出來之後,要求顯示一個老師從什麼時候開始上課,到什麼時候結課,我們就需要將代課時間進行拆分,這樣就不符合第一層範式,因爲數據就不具有了原子性。

解決方案:將表中的代課時間拆分成兩個字段就解決了問題。

 

3、       2NF

第二範式:在數據表的設計當中,如果有複合主鍵(多字段主鍵),且表中有字段並不是由整個主鍵來確定,而是依賴主鍵中的某個字段(主鍵部分):存在字段依賴主鍵的部分的問題,我們將之稱爲部分依賴,第二範式就是不允許部分依賴。

問題:以上表中,因爲講師沒有辦法啊作爲獨立主鍵,需要結合班級才能作爲主鍵(複合主鍵,老師在帶一個班的時候,只帶一個階段的課),代課時間,開始和結束字段都與當前的代課主鍵(講師和班級)有關係,但是性別並不依賴教室,教室不依賴講師,性別只依賴講師,教室只依賴班級。這樣出現了性別和教室依賴主鍵中的一部分;這樣就產生了部分依賴,不符合第二範式。

解決方案:

1)       將性別與講師單獨成表,班級與教室也單獨成表

2)       取消複合主鍵,採用另外與業務不相關的邏輯主鍵。這樣我們就解決了部分依賴的問題(增加單列關鍵字),只要我們不存在複合主鍵,那麼就不會產生部分依賴。

這裏的ID= 講師 + 班級(這樣這條記錄的唯一性的話,我們就不能從數據庫的設計來處理這樣的問題,我們就只能從業務邏輯來處理這樣的問題,比如說將講師和班級設定爲複合唯一鍵)。

4、       4NF

第三範式:要滿足第三範式,就必須西安滿足第二式

第三範式,在理論上來講,我們應該把一張表中的所有字段都直接依賴主鍵(邏輯主鍵,代表的是業務主鍵),如果過數據表的設計過程當中存在一個字段,並不是直接依賴主鍵,而是依賴一個非主鍵字段,最終實現的依賴主鍵,我們將這種依賴稱爲傳遞依賴。這種依賴關係是不符合第三範式的。

第三依賴就是要解決這種傳遞依賴。

    

問題:上表中的設計方案中,是複合第一和第二範式的。但是:性別依賴講師存在,教室依賴班級存在,性別和教室都存在傳遞依賴。我們就要解決這種依賴問題。

解決方案:將存在依賴傳遞的字段,以及依賴的字段本身單獨取出,形成一個單獨的表,然後在需要的對應信息的時候,使用對應的實體表的主鍵將之添加進來。

講師代課表:

Id p

講師id

班級id

代課時間

開始

結束

1

1

10

30天

2.27

5.05

2

2

12

30

2.27

5.05

講師表:(Id= 講師

Id

講師

性別

1

朱元璋

Male

2

李世民

Male

班級表:(ID= 班級

Id

班級

教室

1

Java1501

302

2

Java1502

206

這樣我們就可以看到,將數據分開在之後,我們就可以結束這種傳遞的依賴關係了。

注意:我們在是使用邏輯主鍵的額時候,向數據庫中傳值的時候,是時分方便的,這時候我們就遇到了另外一個問題,採用邏輯主鍵的時候,永遠都不可能解決傳遞依賴。但是我們們應該注意到,實際上能代表記錄含義的,只是表中的業務數據。

è還有很重要的一點是,我們能夠通過一個字段查到的數據,我們就不會重複的設定數據。比如說在代課教師表的時候,我們會發現裏面只有講師id,這是因爲如果在這張表裏面添加姓名這個字段的話,就跟教師表中的教師姓名重複,這就叫做數據的冗餘。

5、       範式的逆規範化

有時候我們在設計表的時候,如果一張表中由幾個字段師需要從另外一張表中去獲得數據信息,理論上講,的確可以後去想要的數據,但是效率會低一點。那麼我們會刻意的在某些表中,不去保存另外表的主鍵(邏輯主鍵),而是直接保存想要的信息,這樣一來,在查詢數據的時候,一張表刻意直接提供數據,而不需要多張表去查詢(效率低)。

這種行爲是一種逆規範化。但是這會導致數據冗餘增加。

 

四、   數據的高級操作

1、       新增數據

基本語法:insert into 表名(字段列表) values (值列表);

在數據插入的時候,假設主鍵對應的值已經存在:那麼數的插入師一定會失敗的。

ð主鍵衝突:當主鍵發生衝突的時候,可以選擇性的進行處理:更新和替換。

1)       主衝突之後的更新操作:

Insert into 表名(字段列表:包含主鍵)values(值列表)on duplicate key update 字段 = 新值;

ð主鍵衝突:替換數據

Replace into 表名 (字段列表:包含主鍵)values (值列表);

ð複製創建表:

Createte table 表名 like 被複製表名;

我們需要注意的是,這樣複製的表實際上只是複製了表的設定,沒有複製表中的數據。

 

 

2)       蠕蟲複製從已有的數據中去獲取數據,然後將數據又進行新增操作:數據會成倍的增加。

Insert into 表名(字段列表)select 字段列表/* from 數據表名;

意義:

(1)        從一張表中複製數據

(2)        可以迅速的讓表中的數據膨脹到一定的數量級,測試表的壓力以及效率。

2、       更新數據

基本語法:update 表名 set 字段 = 值[where條件];

高級新增語法:update 表名 set 字段 = 值[where條件][limit 更新數量];

3、       刪除數據

基本語法:delete from表名 where條件 limit更新數量;

問題:如果表中存在主鍵,那麼當我們刪除之後,自增長是不會還原的。

解決方案:數據的刪除是不會改變表的結構的,只能刪除表後重建。Truncate表名; 先刪除後新增表

 

4、       查詢數據

基本語法:select 字段列表 from 表名(where條件);

完整語法:select[select選項] 字段列表[字段別名] from 數據源 [where條件] [group by子句] [having 子句][order by子句][limit子句];

1)      Select選項:select對查出來的數據的處理方式;

All : 默認的,保留所有結果;

Distinct :去重查出來的結果將重複的記錄去除,所有字段的數都一樣纔算記錄的重複;

 

2)      字段別名:當數據進行查詢的時候,有時候字段名就並不一定滿足需求(多張表進行查詢的時候,很有可能會有同名字段),我們就需要對字段進行重命名。

語法:字段名 as 別名;

 

 

3)      數據源

數據源:數據的來源,關係型數據庫的來源都是數據表:本質上只要保證數據類似二維表,最終都可以作爲數據源。

分類:數據源可以分爲多種:單表數據源,多表數據源,查詢語句。

查詢語句:

A、     單表數據源:select * from 表名;

B、      多表數據源:select * from 表名1,表名2;

多表查詢

從一張表中取出一條記錄,去另外一張表中匹配所有記錄,而且全部保留:(記錄數和字段數),我們將這種結果稱爲笛卡兒積(交叉連接),然而笛卡兒積沒什麼用,所以應該儘量避免。

子查詢:數據的來源是一條查詢語句(查詢語句的結果是一張二維表)

語法:select */字段列表 from(select 語句)as 別名;

注意: 在使用子查詢的時候,這條語句的含義是,從括號裏面已經查詢的內容裏面在進行其他的查詢,也就是說字段列表必須包含在括號裏面的select語句裏面。

問題:在實際應用當中,我們是很少使用子查詢的,因爲這樣的操作很容易就會產生笛卡兒積,射陽會使得程序的效率大大降低。

 

4)      Where子句

概念:用來判讀數據,篩選數據

Where子句返回的結果:0或者1,0代表false,1代表true

判斷條件:

l 比較運算符:<,>,<=,>=,!=,<>(這也是不等於),=,like(模糊匹配),between and(在什麼之間),in,not in

l 邏輯運算符:&&(and), ||(or), ! (not)

l Where 原理:where是唯一一個是直接從磁盤獲取數據的時候就開始判斷的條件,進行where判斷的時候 ,判斷的結果如果成立就保存到內存當中,如果失敗了,就直接放棄。

其他的判斷操作是作用於內存,將數據庫中的數據取出來放到內存當中的之後在進行判斷,最終將判斷結果顯示給用戶。

l Where的好處:不會太佔用內存。

l 範例:

條件查詢1:要求找出學生id爲1或者5的記錄

 

條件查詢2:要求查出年齡在20到34之間的數據

注意:between本是就是閉區間,所以我們就必須保證左邊的比右邊的小或者等於。

問題:當我們輸入的where語句的條件僅僅是非零數那麼會輸出所有的數據。如果是0的話,就會輸出empty set。

 

5)      Group By子句

就是分組的意思,根據某個字段進行分組(相同的放一組,不同的劃分到不同的組)。

基本語法:group by 字段名;但是我們不能簡單通過這樣的方式顯示所有分組後的數據。我們還需要藉助其他的手段才能完成數據的按需顯示。

Sql提供的一系列統計函數:

l Count(): 統計分組之後的數據:每一組有多少記錄。裏面可以使用兩種參數:* 代表統計記錄,字段名代表對應的字段,但是有時候,我們的字段有可能爲空,實際上這個並不會有什麼影響,null是不參與統計的,所以我們並不需要擔心

l Max() :統計字段中的最大值

l Min() :統計字段中的最小值

l Avg() :統計平均值

l Sum() :統計分組之後的和

 

l 多字段分組,先班級,後男女。

假如我們需要知道列表中的複合某種條件的名字。Mysql提供了一個函數,可以分組結果中的摸個字段進行字符串連接(保留改該組中所有的某額字段):group_concat(字段);

 

回溯統計:withrollup:

任何一個分組後的結果,都會有一個小組,最後都需要相上級分組進行彙報統計,根據當前字段分組,這就是回溯統計:回溯統計的時候會將分組字段置空。

多字段回溯統計:

最後再總的數據回溯一次

注意:多字段回溯:考慮到第一層分組會有一次回溯,第二次分組要看第一次分組的組數,組數是多少,回溯就是多少,然後加上第一層回溯即可。

 

6)      Having子句:與where子句一樣:進行條件判斷。Where是針對磁盤數據進行判斷的,但是數據進入到內存時候會進行分組操作,分組結果就需要having來處理數據。Having幾乎能做where能做的事情,但是where卻不能做having能做的事情

A、     分組統計的結果或者說統計函數都只有having能夠使用。

B、      Having能夠使用字段別名,但是where不能因爲where是從磁盤取數據,而名字只可能是字段名,別名是字段進入字段之後才產生的。

5、       Order By子句

Order by排序,根據某個字段進行升序或者降序排序,它一來校對集

基本語法:order by 字段名[asc/desc];  asc是升序(默認的),desc降序。

排序其實可以進行多字段排序:先根據某個字段進行排序,然後再內排。

6、       Limit子句:limit是一種限制結果的語句:限制數量

方案一:只用來限制長度(數量):limit 數據量;

方案二:用來限制起始位置以及數量:limit 其實位置,長度;

方案二實際上主要是要來數據的分頁,多少條進行一次分頁,主要是爲用戶節省時間,爲服務器提高效率,減少資源的浪費。

對於用戶來講:可以點擊的分頁按鈕

對於服務器來講:根據用戶選擇的頁碼來獲取不同的數據:

   Limitoffset ,length;

Length:meyer顯示的數量:基本是不變的。

Offset:起始位置,一般是數量的整數倍(頁碼-1)*每頁顯示量。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章