MySQL 查詢優(yōu)化(十一):使用 MySQL 自定義變量進行查詢優(yōu)化

上篇講到了 MySQL 的冷門知識——自定義變量灶体,估計很少人有用到,但是如果用好了也是可以輔助進行性能優(yōu)化的。需要注意的是變量是基于連接會話的偷拔,而且可能存在一些意外的情況岗喉,需要小心使用。本篇介紹如何利用自定義變量進行查詢優(yōu)化瓶盛,提高效率。

優(yōu)化排序查詢

自定義變量的一個重要特性是你可以同時將該變量的數(shù)學計算后的結果再賦值給該變量,類似于我們的 i = i + 1這種方式惩猫。下面是一個用于計算數(shù)據(jù)表行號的例子:

SET @rownum := 0;
SELECT actor_id, @rownum := @rownum + 1 AS rownum
FROM sakila.actor LIMIT 3;
actor_id rownum
1 1
2 2
3 3

得到的結果也許看起來沒什么意義芝硬,這是因為主鍵是從1自增的,因此行號和主鍵值是一樣的轧房。但是拌阴,這種方式可以用于做排序。例如需要查詢飾演電影數(shù)量最多的前10名演員奶镶,通常的做法是像下面這樣寫:

SELECT actor_id, COUNT(*) as cnt
FROM sakila.film_actor
GROUP BY actor_id
ORDER BY cnt DESC
LIMIT 10;

如果我們要獲得相應的排名值的話迟赃,則可以引入變量來完成:

SET @curr_cnt := 0, @prev_cnt := 0, @rank := 0;
SELECT actor_id,
    @curr_cnt := cnt AS cnt,
  @rank         := IF(@prev_cnt <> @curr_cnt, @rank+1, @rank) as rank,
  @prev_cnt := @curr_cnt AS dummy
FROM (
  SELECT actor_id, COUNT(*) AS cnt
  FROM sakila.film_actor
    GROUP BY actor_id
    ORDER BY cnt DESC
    LIMIT 10
) as der;

這里是將飾演電影的數(shù)量賦值給了 curr_cnt 變量,使用了prev_cnt 存儲前一個演員的參演數(shù)量厂镇。排名從第一名開始的纤壁,如果后面的演員的數(shù)量和前一個演員的數(shù)量不同,則排名要往下(+1)捺信,如果相同則和前一個演員的排名相同酌媒。通過這種方式可以直接從查詢結果中得到演員的排名,而不需要再從數(shù)據(jù)庫查詢做二次處理(當然也可以通過程序代碼實現(xiàn))迄靠。

避免重復獲取剛剛修改的數(shù)據(jù)行

如果想在更新數(shù)據(jù)行的時候再重新獲取數(shù)據(jù)行的信息馍佑,往往需要再讀取一次數(shù)據(jù)庫。這是因為 MySQL 不像 PostgreSQL 的 UPDATE RETURNING 功能可以同時返回更新后的數(shù)據(jù)行梨水,而只是返回更新影響的行數(shù)拭荤。但是,我們可以通過自定義變量完成這樣的操作疫诽。例如舅世,獲取剛剛被修改過更新時間的行,不使用自定義變量的話需要做一次額外的查詢:

UPDATE tb1 SET lastUpdated = NOW() WHERE id = 1;
SELECT lastUpdated FROM tb1 WHERE id = 1;

而使用自定義變量的時候可以避免這種情況:

UPDATE tb1 SET lastUpdated = NOW() WHERE id = 1 AND @now  := NOW();
SELECT @now;

雖然還是有一個查詢操作奇徒,但是后面的查詢操作不再需要訪問數(shù)據(jù)庫了雏亚。

懶加載的聯(lián)合查詢

假設我們需要寫一個聯(lián)合查詢完成如下任務:在聯(lián)合的分支上查找匹配的數(shù)據(jù)行,如果找到了就跳過其他分支摩钙。y這種情況發(fā)生在需要從熱區(qū)數(shù)據(jù)或低頻訪問數(shù)據(jù)中查找(比如近期訂單和歷史訂單)罢低。這是下面針對用戶查詢的一個普通的 SQL:

SELECT id FROM users WHERE  id = 123
UNION ALL
SELECT id FROM users_archived WHERE id = 123;

這個查詢會先從當前正在使用的用戶表查詢 id 為123的用戶,然后 在從已歸檔的用戶表找同樣 id 的用戶胖笛。但是网持,這種寫法比較低效,即便是在 users 表找到了想要找的用戶长踊,還是需要從users_archived 這個表再找一次功舀,而實際用戶 id 為123的只會存在其中的一張表中或兩張表的數(shù)據(jù)是一樣的。通過懶加載的聯(lián)合查詢身弊,可以避免這種情況——只有在第一個分支沒有找到數(shù)據(jù)時才進行第二個分支的查詢辟汰。因此可以使用 MySQL 的 GREATEST 方法來作為查詢結果的容器以避免多返回數(shù)據(jù)列列敲。

SELECT GREATEST(@found := -1, id) AS id, users.name, 'users' as which_tb1
FROM users WHERE id = 123
UNION ALL
    SELECT id, users_archived.name, 'users_archived'
  FROM users_archived WHERE id = 123 AND @found IS NULL
UNION ALL
    SELECT 1, '', 'reset' FROM DUAL WHERE ( @found := NULL) IS NOT NULL;

上述的查詢?nèi)绻谝恍杏薪Y果,則@found 不會被賦值帖汞,因而是 NULL戴而,從而執(zhí)行第二次查詢。而第三次的 UNION 實際沒什么效果翩蘸,只是為了將@found恢復到 NULL 值所意,以便這段 SQL 可以重復執(zhí)行。另一個驗證的方法是對同一張表進行這樣的操作鹿鳖,可以發(fā)現(xiàn)實際只會返回一行數(shù)據(jù)或不返回數(shù)據(jù)(查詢不到數(shù)據(jù)時)扁眯。

SELECT GREATEST(@found := -1, `id`) AS `id`, `infocenter_city`.`name`, 'city' as which_tb1 
FROM `infocenter_city` WHERE `id` = 460100 
UNION ALL 
    SELECT `id`, `infocenter_city`.`name`, 'infocenter_city' 
    FROM `infocenter_city` WHERE id = 460100 AND @found IS NULL 
UNION ALL 
    SELECT 1, '', 'reset' FROM DUAL WHERE ( @found := NULL) IS NOT NULL
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壮莹,一起剝皮案震驚了整個濱河市翅帜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌命满,老刑警劉巖涝滴,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異胶台,居然都是意外死亡歼疮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門诈唬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來韩脏,“玉大人,你說我怎么就攤上這事铸磅∩氖福” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵阅仔,是天一觀的道長吹散。 經(jīng)常有香客問我,道長八酒,這世上最難降的妖魔是什么空民? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮羞迷,結果婚禮上界轩,老公的妹妹穿的比我還像新娘。我一直安慰自己衔瓮,他們只是感情好耸棒,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著报辱,像睡著了一般与殃。 火紅的嫁衣襯著肌膚如雪单山。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天幅疼,我揣著相機與錄音米奸,去河邊找鬼。 笑死爽篷,一個胖子當著我的面吹牛悴晰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逐工,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铡溪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泪喊?” 一聲冷哼從身側響起棕硫,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎袒啼,沒想到半個月后哈扮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡蚓再,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年滑肉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摘仅。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡靶庙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出娃属,到底是詐尸還是另有隱情六荒,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布膳犹,位于F島的核電站恬吕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏须床。R本人自食惡果不足惜铐料,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望豺旬。 院中可真熱鬧钠惩,春花似錦、人聲如沸族阅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坦刀。三九已至愧沟,卻和暖如春蔬咬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沐寺。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工林艘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人混坞。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓狐援,卻偏偏與公主長得像,于是被迫代替她去往敵國和親究孕。 傳聞我的和親對象是個殘疾皇子啥酱,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

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