解析Mysql

sql的執(zhí)行順序:

  • 1 FROM <left_table>
  • 2 WHERE <where_condition>
  • 3 GROUP BY <group_by_list>
  • 4 HAVING <having_condition>
  • 5 SELECT
  • 6 ORDER BY <order_by_condition>
  • 7 LIMIT <limit_number>
  • 8 DISTINCT <select_list>

字段類型的取值范圍

  • 1 bigint 從 -9223372036854775808 到 9223372036854775807 占 8 個字節(jié)
  • 2 int 從-2,147,483,648 到 2,147,483,647 占 4 個字節(jié)
  • 3 mediumint 從-8388608到8388607薄榛,無符號的范圍是0到16777215。 一位大小為3個字節(jié)
  • 4 smallint 從-2^15 (-32,768) 到 2^15 - 1 (32,767) 的整型數(shù)據(jù)又谋,無符號的范圍是0到65535。一位大小占 2 個字節(jié)
  • 5 tinyint 從-128--127爽撒,0~255胎挎。一位大小為 1 字節(jié)
  • 6 varchar
varchar  
字符類型若為gbk,每個字符最多占2個字節(jié)挟冠,最大長度不能超過32766;
字符類型若為utf8鹏漆,每個字符最多占3個字節(jié)巩梢,最大長度不能超過21845
一個字母或數(shù)字占用1個字節(jié)
varchar  (30)  30--90字節(jié)
1個漢字占3個字節(jié)。
批量插入多條數(shù)據(jù)
insert into [tablename] (field1,field2...) values (value1,value12...)
批量插入語句
func insertData() {
    data := []map[string]string{
        {"name": "sos", "email": "87262420@qq.com"},
        {"name": "膩?zhàn)?, "email": "297387990@qq.com"},
        {"name": "領(lǐng)導(dǎo)", "email": "sosmyheart@163.com"},
    }

    sql := "insert into users(name, email) values"
    var valuesList = []interface{}{}

    for index, v := range data{
        if index == len(data)-1{
            sql += "(?,?)"
        }else{
            sql += "(?,?), "
        }
        valuesList = append(valuesList, v["name"], v["email"])
    }
    res, _ := db.Exec(sql, valuesList...) //批量數(shù)據(jù)!
    mainId,_ := res.LastInsertId() //每插入一條數(shù)據(jù)就返回一個表的主鍵id
}

UNION

  • 1 UNION ALL 會導(dǎo)致查詢的數(shù)據(jù)很多重復(fù)的
  • 2 UNION 會做去重處理
  • 3 聯(lián)合查詢的時候艺玲,字段列數(shù)要一致括蝠,而且字段的類型也要一致!
表1
A    B
a    1
b    0
c    3
d    0
e    2

表2
A    B
c    0
e    4

合并兩個表除去重復(fù)的數(shù)據(jù)(以表2的數(shù)據(jù)為主)饭聚,得到以下表
A    B
a    1
b    0
c    0
d    0
e    4

select A,B from 表1 where A not in(select A from 表2)
union
select A,B from 表2

group by / order by 順序問題

  • 1 先分組后排序
  • 2 ORDER BY時不要使用SELECT *忌警,只查需要的字段。

having

  • 1 檢索范圍不一致秒梳,它是在前者查詢完畢的基礎(chǔ)上再進(jìn)行檢索過濾法绵!用于對已分組的數(shù)據(jù)進(jìn)行過濾
  • 2 跟where不是一個范圍,having是在where條件之上進(jìn)行篩選酪碘。
where
select * from table group by 字段 having 字段>10

having
select * from table having sum(字段)>100

聯(lián)合索引--最左匹配原則

  • 1 最左匹配原則是針對聯(lián)合索引來的朋譬,索引的底層是一顆B+樹,構(gòu)建一顆B+樹只能根據(jù)一個值來構(gòu)建兴垦,當(dāng)索引類型為聯(lián)合索引時此熬,數(shù)據(jù)庫會依據(jù)聯(lián)合索引最左的字段來構(gòu)建B+樹,也叫最左匹配原則,聯(lián)合索引其實(shí)可以減少開銷犀忱。

  • 2 最左優(yōu)先。以最左邊的為起點(diǎn)任何連續(xù)的索引都能匹配上扶关。同時遇到范圍查詢(>阴汇、<、between节槐、like)就會停止匹配搀庶。

  • 3 查看是不是用到索引可以使用:EXPLAIN

EXPLAIN SELECT * from test ORDER BY a,b,c desc limit 10
  • 最左匹配原則,可以是在where 或者 group by, order by 之后帶的字段都可以走索引铜异。
image.png
  • 4 根據(jù)type字段來判斷是否使用索引哥倔,下面是性能的大小排列,ALL是最弱的揍庄!
  • 5 index 類型的查詢雖然不是全表掃描, 但是它掃描了所有的索引, 因此比 ALL 類型的稍快.
ALL < index < range ~ index_merge < ref < eq_ref < const < system
  • 6 索引列越多咆蒿,通過索引篩選出的數(shù)據(jù)越少。有1000W條數(shù)據(jù)的表蚂子,有如下SQL: select from table where col1=1 and col2=2 and col3=3沃测,假設(shè)假設(shè)每個條件可以篩選出10%的數(shù)據(jù),如果只有單值索引食茎,那么通過該索引能篩選出1000W10%=100w條數(shù)據(jù)蒂破,然后再回表從100w條數(shù)據(jù)中找到符合col2=2 and col3=3的數(shù)據(jù),然后再排序别渔,再分頁附迷;如果是聯(lián)合索引,通過索引篩選1000w10%10%10%=1w哎媚,效率提升可想而知

  • 7 聯(lián)合索引就是按照第一列進(jìn)行排序喇伯,然后第一列排好序的基礎(chǔ)上再對第二列進(jìn)行排序,以此類推抄伍。如果沒有第一列直接訪問第二列艘刚,第二列肯定是無序的,直接訪問后面的列就用不到索引了截珍。

低粒度的鎖--RWMutex (讀寫鎖)

  • 1 讀寫鎖--可以并發(fā)多個讀操作攀甚,但是寫是互斥的,當(dāng)goroutine進(jìn)行寫操作時岗喉,其他goroutine既不能讀也不能寫秋度,都是阻塞!

  • 2 多個goroutine并發(fā)獲取讀鎖的時候钱床,有g(shù)oroutine要獲取寫鎖荚斯,這時候?qū)戞i的線程是阻塞的,后面如果還有g(shù)oroutine想要獲取讀鎖也是阻塞的~!

  • 3 當(dāng)一個goroutine獲取寫鎖后事期,其他想要獲取讀鎖和寫鎖的都會阻塞

  • 4 讀鎖是可重入鎖滥壕,同一個goroutine可以多次獲取讀鎖。同理兽泣,當(dāng)一個線程獲取到了寫鎖后嘗試獲取讀鎖绎橘,會造成死鎖錯誤。

  • 5 讀寫鎖跟互斥鎖的區(qū)別在于:鎖的粒度減少唠倦,讀寫鎖可以讓多個goroutine獲取共享資源時同時獲取讀鎖称鳞。而互斥鎖在并發(fā)獲取共享資源的時候,只能讓一個goroutine獲取讀鎖稠鼻,其他goroutine阻塞冈止。影響性能!

sync.Mutex的操作

  • 1 由于是并發(fā)的寫數(shù)據(jù),多個goroutine爭搶資源候齿,修改數(shù)據(jù)熙暴,最后count累加的結(jié)果并不是10000
func main() {
    var count = 0
    var wg sync.WaitGroup
    //十個協(xié)程數(shù)量
    n := 10
    wg.Add(n)
    for i := 0; i < n; i++ {
        go func() {
            //1萬疊加
            for j := 0; j < 10000; j++ {
                count++
            }
            defer wg.Done()
        }()
    }
    wg.Wait()
    fmt.Println(count)
}
  • 2 加上互斥鎖后就能保證在寫操作的時候,保證沒有其他goroutine會篡改
func main() {
    var count = 0
    var wg sync.WaitGroup
    //十個協(xié)程數(shù)量
    n := 10
    m := sync.Mutex{}
    wg.Add(n)
    for i := 0; i < n; i++ {
        go func() {
            //1萬疊加
            for j := 0; j < 10000; j++ {
                m.Lock()
                count++
                m.Unlock()
            }
            defer wg.Done()
        }()
    }
    wg.Wait()
    fmt.Println(count)  10000
}

sync.RWMutex

  • 1 前提是明確知道當(dāng)下的應(yīng)用場景毛肋,是大量的讀和少量寫怨咪,就可以用RWMutex替代 Mutex

  • 2 包括的方法: Lock/Unlock --- 針對寫操作,后面來的資源都會阻塞润匙,知道執(zhí)行Unlock()釋放鎖诗眨。

  • 3 RLock/RUnlock:針對讀操作的方法,當(dāng)鎖被讀操作獲取的時候孕讳,RLock方法會直接返回匠楚。如果是被寫操作獲取的時候,RLock方法會一直阻塞厂财,直到RUnlock釋放鎖芋簿。

  • 4 并發(fā)讀

func main() {
    go reads(1)
    go reads(2)
    go reads(3)

    time.Sleep(time.Second * 3)
}
func reads(num int) {
    var m sync.RWMutex
    fmt.Println("reads start")
    m.RLock()
    fmt.Println(num, "reads")
    time.Sleep(time.Second * 2)
    m.RUnlock()
    fmt.Println(num, "reads end~!")
}
  • 5 并發(fā)寫的場景, 寫的時候其他協(xié)程阻塞
func main() {
    var m sync.RWMutex
    for i := 1; i <= 3; i++ {
        go writes(&m, i)
    }
    for j := 1; j <= 3; j++ {
        go reads(&m, j)
    }
    time.Sleep(time.Second * 2)
    fmt.Println("do work end~", count)
}

func reads(m *sync.RWMutex, num int) {
    fmt.Println("reads start")
    m.RLock()
    fmt.Println("read下標(biāo):", num, count)
    time.Sleep(1 * time.Millisecond)
    m.RUnlock()
}
func writes(m *sync.RWMutex, j int) {
    fmt.Println("write start")
    m.Lock()
    count++
    fmt.Println("write下標(biāo):", j, count)
    time.Sleep(1 * time.Millisecond)
    m.Unlock()
}
// 控制臺輸出結(jié)果
write start
write start
write下標(biāo): 1 1  并發(fā)寫會阻塞
reads start
write start
reads start
reads start
read下標(biāo): 2 1   并發(fā)讀可以直接返回
read下標(biāo): 3 1
read下標(biāo): 1 1
write下標(biāo): 2 2
write下標(biāo): 3 3
do work end~ 3

事務(wù)

  • 1 事務(wù)默認(rèn)是系統(tǒng)自動提交的!
  • 2 事務(wù)的四大特性:原子性(不可拆分)璃饱,一致性(結(jié)果一致)与斤,隔離性(獨(dú)立操作),持久性(永久存儲在磁盤)
  • 3 開始事務(wù)命令:start transaction 或者 begin

并發(fā)事務(wù)引發(fā)的問題

  • 1 臟讀:一個事務(wù)讀到另一個事務(wù)沒有提交的數(shù)據(jù)
  • 2 不可重復(fù)讀:一個事務(wù)先后讀取同一條記錄荚恶,但是2個結(jié)果不一致
  • 3 幻讀:一個事務(wù)在查詢該條記錄時沒有發(fā)現(xiàn)數(shù)據(jù)存在撩穿,但是在插入數(shù)據(jù)的時候,又發(fā)現(xiàn)已經(jīng)存在谒撼,產(chǎn)生幻覺食寡,也就是幻讀。

事務(wù)的隔離級別就是解決事務(wù)并發(fā)的問題

  • 1 read uncommited(讀未提交)廓潜,所有并發(fā)問題都會產(chǎn)生抵皱。
  • 2 read commited (讀已提交)善榛,會產(chǎn)生不可重復(fù)讀和幻讀。
  • 3 repeatable read(默認(rèn):可重復(fù)讀)呻畸,會產(chǎn)生幻讀的問題移盆。
  • 4 serializable (串行化),可以解決所有并發(fā)問題伤为,但是性能是最慢的味滞。

Mysql 結(jié)構(gòu)

  • 4層結(jié)構(gòu)


    1709379398248.jpg
  • 存儲引擎是針對表的,不是庫的钮呀。
  • 不同的引擎有不一樣的應(yīng)用場景。
  • 5.5版本之后的Mysql默認(rèn)引擎是: InnoDB昨凡。
  • Memory引擎 : 數(shù)據(jù)是存放在內(nèi)存中爽醋,速度快,使用這個引擎的時候該表只能作為臨時表或者緩存來用便脊!


    image.png

索引的數(shù)據(jù)結(jié)構(gòu)

  • Innodb 引擎的索引是用B+Tree 結(jié)構(gòu):所有葉子節(jié)點(diǎn)存放數(shù)據(jù)蚂四,非葉子節(jié)點(diǎn)存索引,葉子節(jié)點(diǎn)形成雙向鏈表哪痰。所有數(shù)據(jù)都存在一個空間:表空間---段---區(qū)---頁---行遂赠,它們是層層包含的關(guān)系。
  • Innodb的3大特性:事務(wù)晌杰,外鍵跷睦,行鎖

-
image.png
  • 一個頁的空間大小是16KB
  • B+Tree相比于二叉樹來說的優(yōu)點(diǎn):層級少,搜索速度快

索引分類

image.png
image.png
  • 聚集索引掛的是表里的這一行的行數(shù)據(jù)

  • 二級索引掛的是聚集索引的ID肋演,也就是通過這個id去聚集索引下面檢索數(shù)據(jù)抑诸,2個索引都是B+Tree結(jié)構(gòu)

  • 下面這個查詢語句先走二級索引,找到對應(yīng)的鍵值再去聚集索引里找對應(yīng)的數(shù)據(jù)!這個過程叫做回表查詢爹殊!


    image.png
  • 指針比Key要多一個蜕乡,一個指針是占6字節(jié),而Key值要根據(jù)具體類型來計(jì)算梗夸,比如一個bigint占8字節(jié)层玲。

Query 查詢語句優(yōu)化

  • 可以通過查詢語句查看sql語句的執(zhí)行具體情況,以便做性能優(yōu)化反症。
show global status like `Com______`; // 7個橫杠
image.png

Explain 檢測sql語句的性能

  • 可以通過Explain 來查看Type字段下的索引是什么辛块,如果是All就代表查詢性能最差,可以對Sql進(jìn)行優(yōu)化惰帽。

  • 創(chuàng)建索引命令: create index idx_sn on 表名(字段名)

  • 最左匹配原則是針對聯(lián)合索引來的憨降,如果沒有走最左匹配就會全表掃描,用不上索引性能就會差一點(diǎn)该酗!如果查詢多個字段授药,并且跳過了索引中的列士嚎,那索引會部分失效,前提是走了聯(lián)合索引悔叽,也就是最左匹配走了莱衩。

  • 當(dāng)出現(xiàn)比較范圍查詢時,最好加上 >= 可以規(guī)避索引失效問題!


    image.png
  • 盡量不要進(jìn)行函數(shù)運(yùn)算娇澎,否則索引會失效笨蚁。

  • 查詢的時候,如果DB里存的是字符串趟庄,查詢語句沒有加引號括细,也會導(dǎo)致索引失效,檢索效率降低戚啥。


    image.png
  • 頭部模糊匹配奋单,索引會失效。


    1709555920234.jpg

索引提示性使用

  • use index (標(biāo)識使用具體那個索引)
  • ignore index (忽略使用某索引)
  • force index (強(qiáng)制使用某索引)
Explain select * from user ignore index(索引名) where phone="xxxx"
  • 覆蓋索引:就是回表查詢的時候一次就查詢到數(shù)據(jù)猫十,不需要再去聚集索引檢索數(shù)據(jù)
這種情況要優(yōu)化的話览濒,最好是建立聯(lián)合索引走覆蓋索引檢索數(shù)據(jù),不需要回表二次查詢拖云,性能是最優(yōu)贷笛!
- select id,username,password from user where password ="xxxx"
  • 前綴索引:是用在查詢某字段,因數(shù)據(jù)太長或者文本體積太大宙项,而截取其中一小段建立索引乏苦,來提高檢索速度的!
image.png

Limit優(yōu)化

  • 可以采用子查詢的方式進(jìn)行優(yōu)化(數(shù)據(jù)量特別大的時候)


    image.png

Count優(yōu)化

  • 遇到數(shù)據(jù)量大的情況杉允,count可以存redis邑贴,每次插入一條數(shù)據(jù)就累加,自己維護(hù)一個總數(shù)叔磷,當(dāng)數(shù)據(jù)量大時去Mysql查詢會比較慢
  • count查詢的效率對比:
count(字段) < count(主鍵id) < count(1) < count(*) # count(*)是最快的拢驾,Innodb專門針對count(*)進(jìn)行了優(yōu)化,不需要累加計(jì)數(shù)

Update 優(yōu)化

  • Innodb的行鎖是針對索引加的改基,不是針對記錄加的鎖繁疤,并且索引不能失效,否則行鎖會升級成表鎖秕狰,也就是當(dāng)insert操作的時候會鎖住一整張表稠腊,其他操作提交不了。并發(fā)性能就會降低

按照鎖的粒度劃分

  • 全局鎖:開啟全局鎖時鸣哀,不能進(jìn)行增刪改操作架忌,只能進(jìn)行查詢操作。

  • 表級鎖:表鎖又細(xì)分寫和讀鎖我衬,同樣開啟讀鎖是叹放,其他DML操作阻塞饰恕,開啟寫鎖時,其他的DML和DQL都不能操作井仰。

  • 行級鎖: 行鎖鎖的是索引埋嵌,不是葉子節(jié)點(diǎn)的數(shù)據(jù)。

  • 當(dāng)操作的字段沒有索引俱恶,開啟事務(wù)操作的時候行鎖就會升級成表鎖雹嗦,其他操作會阻塞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末合是,一起剝皮案震驚了整個濱河市了罪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌聪全,老刑警劉巖捶惜,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異荔烧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)汽久,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門鹤竭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人景醇,你說我怎么就攤上這事臀稚。” “怎么了三痰?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵吧寺,是天一觀的道長。 經(jīng)常有香客問我散劫,道長稚机,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任获搏,我火速辦了婚禮赖条,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘常熙。我一直安慰自己纬乍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布裸卫。 她就那樣靜靜地躺著仿贬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪墓贿。 梳的紋絲不亂的頭發(fā)上茧泪,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天蜓氨,我揣著相機(jī)與錄音,去河邊找鬼调炬。 笑死语盈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缰泡。 我是一名探鬼主播刀荒,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼棘钞!你這毒婦竟也來了缠借?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤宜猜,失蹤者是張志新(化名)和其女友劉穎泼返,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姨拥,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绅喉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叫乌。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柴罐。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖憨奸,靈堂內(nèi)的尸體忽然破棺而出革屠,到底是詐尸還是另有隱情,我是刑警寧澤排宰,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布似芝,位于F島的核電站酪耳,受9級特大地震影響畅买,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜姊舵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一盐类、第九天 我趴在偏房一處隱蔽的房頂上張望麻诀。 院中可真熱鬧,春花似錦傲醉、人聲如沸蝇闭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呻引。三九已至,卻和暖如春吐咳,著一層夾襖步出監(jiān)牢的瞬間逻悠,已是汗流浹背元践。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留童谒,地道東北人单旁。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像饥伊,于是被迫代替她去往敵國和親象浑。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容