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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

sql 非主键每年自增_或许你不知道的 10 条 SQL 技巧

發(fā)布時(shí)間:2023/12/2 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 sql 非主键每年自增_或许你不知道的 10 条 SQL 技巧 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上文我們簡(jiǎn)述了 SQL 的一些進(jìn)階技巧,一些朋友覺(jué)得不過(guò)癮,我們繼續(xù)來(lái)下篇,再送你 10 個(gè)技巧

一、 使用延遲查詢優(yōu)化 limit [offset], [rows]

經(jīng)常出現(xiàn)類似以下的 SQL 語(yǔ)句:

SELECT?*?FROM?film?LIMIT?100000,?10

offset 特別大!

這是我司出現(xiàn)很多慢 SQL 的主要原因之一,尤其是在跑任務(wù)需要分頁(yè)執(zhí)行時(shí),經(jīng)常跑著跑著 offset 就跑到幾十萬(wàn)了,導(dǎo)致任務(wù)越跑越慢。

LIMIT 能很好地解決分頁(yè)問(wèn)題,但如果 offset 過(guò)大的話,會(huì)造成嚴(yán)重的性能問(wèn)題,原因主要是因?yàn)?MySQL 每次會(huì)把一整行都掃描出來(lái),掃描 offset 遍,找到 offset 之后會(huì)拋棄 offset 之前的數(shù)據(jù),再?gòu)?offset 開(kāi)始讀取 10 條數(shù)據(jù),顯然,這樣的讀取方式問(wèn)題。

可以通過(guò)延遲查詢的方式來(lái)優(yōu)化

假設(shè)有以下 SQL,有組合索引(sex, rating)

SELECT??FROM?profiles?where?sex='M'?order?by?rating?limit?100000,?10;

則上述寫法可以改成如下寫法

SELECT??FROM?profiles?inner?join
(SELECT?id?form?FROM?profiles?where?x.sex='M'?order?by?rating?limit?100000,?10)as?x?using(id);

這里利用了覆蓋索引的特性,先從覆蓋索引中獲取 100010 個(gè) id,再丟充掉前 100000 條 id,保留最后 10 個(gè) id 即可,丟掉 100000 條 id 不是什么大的開(kāi)銷,所以這樣可以顯著提升性能

二、 利用 LIMIT 1 取得唯一行

數(shù)據(jù)庫(kù)引擎只要發(fā)現(xiàn)滿足條件的一行數(shù)據(jù)則立即停止掃描,,這種情況適用于只需查找一條滿足條件的數(shù)據(jù)的情況

三、 注意組合索引,要符合最左匹配原則才能生效

假設(shè)存在這樣順序的一個(gè)聯(lián)合索引“col_1, col_2, col_3”。這時(shí),指定條件的順序就很重要。

○?SELECT?*?FROM?SomeTable?WHERE?col_1?=?10?AND?col_2?=?100?AND?col_3?=?500;
○?SELECT?*?FROM?SomeTable?WHERE?col_1?=?10?AND?col_2?=?100?;
×?SELECT?*?FROM?SomeTable?WHERE?col_2?=?100?AND?col_3?=?500?;

前面兩條會(huì)命中索引,第三條由于沒(méi)有先匹配 col_1,導(dǎo)致無(wú)法命中索引, 另外如果無(wú)法保證查詢條件里列的順序與索引一致,可以考慮將聯(lián)合索引 拆分為多個(gè)索引。

四、使用 LIKE 謂詞時(shí),只有前方一致的匹配才能用到索引(最左匹配原則)

×?SELECT?*?FROM?SomeTable?WHERE?col_1?LIKE?'%a';
×?SELECT?*?FROM?SomeTable?WHERE?col_1?LIKE?'%a%';
○?SELECT?*?FROM?SomeTable?WHERE?col_1?LIKE?'a%';

上例中,只有第三條會(huì)命中索引,前面兩條進(jìn)行后方一致或中間一致的匹配無(wú)法命中索引

五、 簡(jiǎn)單字符串表達(dá)式

模型字符串可以使用 _ 時(shí), 盡可能避免使用 %, 假設(shè)某一列上為 char(5)

不推薦

SELECT?
????first_name,?
????last_name,
????homeroom_nbr
??FROM?Students
?WHERE?homeroom_nbr?LIKE?'A-1%';

推薦

SELECT?first_name,?last_name
homeroom_nbr
??FROM?Students
?WHERE?homeroom_nbr?LIKE?'A-1__';?--模式字符串中包含了兩個(gè)下劃線

六、盡量使用自增 id 作為主鍵

比如現(xiàn)在有一個(gè)用戶表,有人說(shuō)身份證是唯一的,也可以用作主鍵,理論上確實(shí)可以,不過(guò)用身份證作主鍵的話,一是占用空間相對(duì)于自增主鍵大了很多,二是很容易引起頻繁的頁(yè)分裂,造成性能問(wèn)題(什么是頁(yè)分裂,請(qǐng)參考這篇文章)

主鍵選擇的幾個(gè)原則:自增,盡量小,不要對(duì)主鍵進(jìn)行修改

七、如何優(yōu)化 count(*)

使用以下 sql 會(huì)導(dǎo)致慢查詢

SELECT?COUNT(*)?FROM?SomeTable
SELECT?COUNT(1)?FROM?SomeTable

原因是會(huì)造成全表掃描,有人說(shuō) COUNT(*) 不是會(huì)利用主鍵索引去查找嗎,怎么還會(huì)慢,這就要談到 MySQL 中的聚簇索引和非聚簇索引了,聚簇索引葉子節(jié)點(diǎn)上存有主鍵值+整行數(shù)據(jù),非聚簇索葉子節(jié)點(diǎn)上則存有輔助索引的列值 + 主鍵值,如下

所以就算對(duì) COUNT(*) 使用主鍵查找,由于每次取出主鍵索引的葉子節(jié)點(diǎn)時(shí),取的是一整行的數(shù)據(jù),效率必然不高,但是非聚簇索引葉子節(jié)點(diǎn)只存儲(chǔ)了「列值 + 主鍵值」,這也啟發(fā)我們可以用非聚簇索引來(lái)優(yōu)化,假設(shè)表有一列叫 status, 為其加上索引后,可以用以下語(yǔ)句優(yōu)化:

SELECT?COUNT(status)?FROM?SomeTable

有人曾經(jīng)測(cè)過(guò)(見(jiàn)文末參考鏈接),假設(shè)有 100 萬(wàn)行數(shù)據(jù),使用聚簇索引來(lái)查找行數(shù)的,比使用 COUNT(*) 查找速度快 10 幾倍。不過(guò)需要注意的是通過(guò)這種方式無(wú)法計(jì)算出 ?status 值為 null 的那些行

如果主鍵是連續(xù)的,可以利用 MAX(id) 來(lái)查找,MAX 也利用到了索引,只需要定位到最大 id 即可,性能極好,如下,秒現(xiàn)結(jié)果

SELECT?MAX(id)?FROM?SomeTable

說(shuō)句題句話,有人說(shuō)用 MyISAM 引擎調(diào)用 COUNT(*) 非常快,那是因?yàn)樗崆鞍研袛?shù)存在磁盤中了,直接拿,當(dāng)然很快,不過(guò)如果有 WHERE 的限制,用 COUNT(*) 還是很慢!

八、避免使用 SELECT * ,盡量利用覆蓋索引來(lái)優(yōu)化性能

SELECT * 會(huì)提取出一整行的數(shù)據(jù),如果查詢條件中用的是組合索引進(jìn)行查找,還會(huì)導(dǎo)致回表(先根據(jù)組合索引找到葉子節(jié)點(diǎn),再根據(jù)葉子節(jié)點(diǎn)上的主鍵回表查詢一整行),降低性能,而如果我們所要的數(shù)據(jù)就在組合索引里,只需讀取組合索引列,這樣網(wǎng)絡(luò)帶寬將大大減少,假設(shè)有組合索引列 (col_1, col_2)

推薦用

SELECT?col_1,?col_2?
??FROM?SomeTable?
?WHERE?col_1?=?xxx?AND?col_2?=?xxx

不推薦用

SELECT?*
??FROM?SomeTable?
?WHERE?col_1?=?xxx?AND??col_2?=?xxx

九、 如有必要,使用 force index() 強(qiáng)制走某個(gè)索引

業(yè)務(wù)團(tuán)隊(duì)曾經(jīng)出現(xiàn)類似以下的慢 SQL 查詢

SELECT?*
??FROM??SomeTable
?WHERE?`status`?=?0
???AND?`gmt_create`?>?1490025600
???AND?`gmt_create`?1490630400
???AND?`id`?>?0
???AND?`post_id`?IN?('67778',?'67811',?'67833',?'67834',?'67839',?'67852',?'67861',?'67868',?'67870',?'67878',?'67909',?'67948',?'67951',?'67963',?'67977',?'67983',?'67985',?'67991',?'68032',?'68038'/*...?omitted?480?items?...*/)
order?by?id?asc?limit?200;

post_id 也加了索引,理論上走 post_id 索引會(huì)很快查詢出來(lái),但實(shí)際通過(guò) EXPLAIN 發(fā)現(xiàn)走的卻是 id 的索引(這里隱含了一個(gè)常見(jiàn)考點(diǎn),在多個(gè)索引的情況下, MySQL 會(huì)如何選擇索引),而 id > 0 這個(gè)查詢條件沒(méi)啥用,直接導(dǎo)致了全表掃描, 所以在有多個(gè)索引的情況下一定要慎用,可以使用 force index 來(lái)強(qiáng)制走某個(gè)索引,以這個(gè)例子為例,可以強(qiáng)制走 post_id 索引,效果立桿見(jiàn)影。

這種由于表中有多個(gè)索引導(dǎo)致 MySQL 誤選索引造成慢查詢的情況在業(yè)務(wù)中也是非常常見(jiàn),一方面是表索引太多,另一方面也是由于 SQL 語(yǔ)句本身太過(guò)復(fù)雜導(dǎo)致, 針對(duì)本例這種復(fù)雜的 SQL 查詢,其實(shí)用 ElasticSearch 搜索引擎來(lái)查找更合適,有機(jī)會(huì)到時(shí)出一篇文章說(shuō)說(shuō)。

十、 使用 EXPLAIN 來(lái)查看 SQL 執(zhí)行計(jì)劃

上個(gè)點(diǎn)說(shuō)了,可以使用 EXPLAIN 來(lái)分析 SQL 的執(zhí)行情況,如怎么發(fā)現(xiàn)上文中的最左匹配原則不生效呢,執(zhí)行 「EXPLAIN + SQL 語(yǔ)句」可以發(fā)現(xiàn) key 為 None ,說(shuō)明確實(shí)沒(méi)有命中索引

我司在提供 SQL 查詢的同時(shí),也貼心地加了一個(gè) EXPLAIN 功能及 sql 的優(yōu)化建議,建議各大公司效仿 ^_^,如圖示

十一、 批量插入,速度更快

當(dāng)需要插入數(shù)據(jù)時(shí),批量插入比逐條插入性能更高

推薦用

--?批量插入
INSERT?INTO?TABLE?(id,?user_id,?title)?VALUES?(1,?2,?'a'),(2,3,'b');

不推薦用

INSERT?INTO?TABLE?(id,?user_id,?title)?VALUES?(1,?2,?'a');
INSERT?INTO?TABLE?(id,?user_id,?title)?VALUES?(2,3,'b');

批量插入 SQL 執(zhí)行效率高的主要原因是合并后日志量 MySQL 的 binlog 和 innodb 的事務(wù)讓日志減少了,降低日志刷盤的數(shù)據(jù)量和頻率,從而提高了效率

十二、 慢日志 SQL 定位

前面我們多次說(shuō)了 SQL 的慢查詢,那么該怎么定位這些慢查詢 SQL 呢,主要用到了以下幾個(gè)參數(shù)

這幾個(gè)參數(shù)一定要配好,再根據(jù)每條慢查詢對(duì)癥下藥,像我司每天都會(huì)把這些慢查詢提取出來(lái)通過(guò)郵件給形式發(fā)送給各個(gè)業(yè)務(wù)團(tuán)隊(duì),以幫忙定位解決

總結(jié)

業(yè)務(wù)生產(chǎn)中可能還有很多 CASE 導(dǎo)致了慢查詢,其實(shí)細(xì)細(xì)品一下,都會(huì)發(fā)現(xiàn)這些都和 MySQL 索引的底層數(shù)據(jù) B+ 樹(shù) 有莫大的關(guān)系,強(qiáng)烈建議大家看一下我的另一篇介紹 B+ 樹(shù)的文章,好評(píng)如潮!相信大家看了之后,以上出現(xiàn)的問(wèn)題會(huì)有一個(gè)更深層次的理解,掌握底層,以不變應(yīng)萬(wàn)變!

你心里沒(méi)點(diǎn) B + 樹(shù)嗎?

最后,歡迎大家關(guān)注公號(hào),共同交流

???●MySQL 可重復(fù)讀,差點(diǎn)就讓我背上了一個(gè) P0 事故!●或許你不知道的 15 條 SQL 技巧●一條SQL查詢語(yǔ)句是如何執(zhí)行的?

覺(jué)得不錯(cuò),點(diǎn)個(gè)在看~

總結(jié)

以上是生活随笔為你收集整理的sql 非主键每年自增_或许你不知道的 10 条 SQL 技巧的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。