最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mysql嵌套查詢和聯(lián)表查詢優(yōu)化方法

 更新時(shí)間:2013年02月28日 10:44:51   作者:  
本文描述了mysql嵌套查詢和聯(lián)表查詢優(yōu)化的方法,有些情況可以使用這種優(yōu)化方法,而有些情況,這種方法就無能為力了
嵌套查詢?cè)愀獾膬?yōu)化
在上面我提到過,不考慮特殊的情況,聯(lián)表查詢要比嵌套查詢更有效。盡管兩條查詢表達(dá)的是同樣的意思,盡管你的計(jì)劃是告訴服務(wù)器要做什么,然后讓它決定怎么做,但有時(shí)候你非得告訴它改怎么做。否則優(yōu)化器可能會(huì)做傻事。我最近就碰到這樣的情況。這幾個(gè)表是三層分級(jí)關(guān)系:category, subcategory和item。有幾千條記錄在category表,幾百條記錄在subcategory表,以及幾百萬條在item表。你可以忽略category表了,我只是交代一下背景,以下查詢語句都不涉及到它。這是創(chuàng)建表的語句:

[sql]
復(fù)制代碼 代碼如下:

create table subcategory ( 
    id int not null primary key, 
    category int not null, 
    index(category) 
) engine=InnoDB; 

create table item( 
    id int not null auto_increment primary key, 
    subcategory int not null, 
    index(subcategory) 
) engine=InnoDB; 
 

我又往表里面填入一些樣本數(shù)據(jù)   

[sql]
復(fù)制代碼 代碼如下:

insert into subcategory(id, category) 
    select i, i/100 from number 
    where i <= 300000; 

insert into item(subcategory) 
    select id 
    from ( 
        select id, rand() * 20 as num_rows from subcategory 
    ) as x 
        cross join number 
    where i <= num_rows; 

create temporary table t as 
    select subcategory from item 
    group by subcategory 
    having count(*) = 19 
    limit 100; 

insert into item (subcategory) 
    select subcategory 
    from t 
        cross join number 
    where i < 2000; 
 

再次說明,這些語句運(yùn)行完需要一點(diǎn)時(shí)間,不適合放在產(chǎn)品環(huán)境中運(yùn)行。思路是往item里插入隨機(jī)行數(shù)的數(shù)據(jù),這樣subcategory就有1到2018之間個(gè)item。這不是實(shí)際中的完整數(shù)據(jù),但效果一樣。

我想找出某個(gè)category中item數(shù)大于2000的全部subcategory。首先,我找到一個(gè)subcategory item數(shù)大于2000的,然后把它的category用在接下來的查詢中。這是具體的查詢語句:

[sql]
復(fù)制代碼 代碼如下:

select c.id 
from subcategory as c 
    inner join item as i on i.subcategory = c.id 
group by c.id 
having count(*) > 2000; 

-- choose one of the results, then 
select * from subcategory where id = ???? 
-- result: category = 14 
 

我拿到一個(gè)合適的值14,在以下的查詢中會(huì)用到它。這是用來查詢category 14 中所有item數(shù)大于2000的subcategory的語句:

[sql]
復(fù)制代碼 代碼如下:

select c.id 
from subcategory as c 
    inner join item as i on i.subcategory = c.id 
where c.category = 14 
group by c.id 
having count(*) > 2000; 
 

在我的樣例數(shù)據(jù)里,查詢的結(jié)果有10行記錄,而且只用10多秒就完成了。EXPLAIN顯示出很好地使用了索引;從數(shù)據(jù)的規(guī)模來看,相當(dāng)不錯(cuò)了。查詢計(jì)劃是在索引上遍歷并計(jì)算出目標(biāo)記錄。目前為止,非常好。

這回假設(shè)我要從subcategory取出全部的字段。我可以把上面的查詢當(dāng)成嵌套,然后用JOIN,或者SELECT MAX之類(既然分組集對(duì)應(yīng)的值都是唯一的),但也寫成跟下面的一樣的,有木有?

[sql]
復(fù)制代碼 代碼如下:

select * from subcategory 
where id in ( 
    select c.id 
    from subcategory as c 
        inner join item as i on i.subcategory = c.id 
    where c.category = 14 
    group by c.id 
    having count(*) > 2000 
); 
 

跑完這條查詢估計(jì)要從破曉到夕陽沉入大地。我不知道它要跑多久,因?yàn)槲覜]打算讓它無休止地跑下去。你可能認(rèn)為,單從語句上理解,它會(huì):a)計(jì)算出里面的查詢,找出那10個(gè)值,b)繼續(xù)找出那10條記錄,并且在primary索引上去找會(huì)非常地快。錯(cuò),這是實(shí)際上的查詢計(jì)劃:

[sql]
復(fù)制代碼 代碼如下:

*************************** 1. row *************************** 
           id: 1 
  select_type: PRIMARY 
        table: subcategory 
         type: ALL 
possible_keys: NULL 
          key: NULL 
      key_len: NULL 
          ref: NULL 
         rows: 300783 
        Extra: Using where 
*************************** 2. row *************************** 
           id: 2 
  select_type: DEPENDENT SUBQUERY 
        table: c 
         type: ref 
possible_keys: PRIMARY,category 
          key: category 
      key_len: 4 
          ref: const 
         rows: 100 
        Extra: Using where; Using index; Using temporary; Using filesort 
*************************** 3. row *************************** 
           id: 2 
  select_type: DEPENDENT SUBQUERY 
        table: i 
         type: ref 
possible_keys: subcategory 
          key: subcategory 
      key_len: 4 
          ref: c.id 
         rows: 28 
        Extra: Using index 
 

如何你不熟悉如何分析mysql的語句查詢計(jì)劃,請(qǐng)看大概意思:mysql計(jì)劃從外到內(nèi)執(zhí)行查詢,而不是從內(nèi)到外。我會(huì)一個(gè)一個(gè)地介紹查詢的每個(gè)部分。

外面的查詢簡(jiǎn)單地變成了SELECT * FROM subcategory。雖然里面的查詢對(duì)subcategory有個(gè)約束(WHERE category = 14),但出于某些原因mysql沒有將它作用于外面的查詢。我不知道是神馬原因。我只知道它掃描了整張表(這就是 type:ALL 表示的意思),并且沒有使用任何的索引。這是在10幾萬行記錄的表上掃描。

在外面的查詢,對(duì)每行都執(zhí)行一次里面的查詢,盡管沒有值被里面的查詢使用到,因?yàn)槔锩娴牟樵儽弧皟?yōu)化”成引用外面的查詢。照此分析,查詢計(jì)劃變成了嵌套循環(huán)。外面的查詢的每一次循環(huán),都執(zhí)行一次里面的查詢。下面就是優(yōu)化器重寫后的查詢計(jì)劃:

[sql]
復(fù)制代碼 代碼如下:

select * from subcategory as s 
where <in_optimizer>( 
   s.id,<exists>( 
   select c.id 
   from subcategory as c 
      join item as i 
   where ((i.subcategory = c.id) and (c.category = 14)) 
   group by c.id 
   having ((count(0) > 2000) 
      and (<cache>(s.id) = <ref_null_helper>(c.id)))) 

 

你可以通過在EXPLAIN EXTENDED 后面帶上SHOW WARNINGS 得到優(yōu)化后的查詢。請(qǐng)留意在HAVING子句中指向的外部域。

我舉這個(gè)例子并非有意抨擊mysql的優(yōu)化策略。眾所皆知mysql在有些情況下還不能很好地優(yōu)化嵌套查詢,這個(gè)問題已經(jīng)被廣泛報(bào)告過。我想指出的是,開發(fā)者有必要檢查查詢語句確保它們不是被糟糕地優(yōu)化。大多數(shù)情況下,安全起見若非是非必要,避免使用嵌套——尤其是WHERE...IN() 和 WHERE...NOT IN語句。

我自己的原則是“有疑問,EXPLAIN看看”。如果面對(duì)的是一個(gè)大數(shù)據(jù)表,我會(huì)自然而然地產(chǎn)生疑問。

如何強(qiáng)制里面的查詢先執(zhí)行
上一節(jié)中的語句撞板只因?yàn)閙ysql把它當(dāng)成相關(guān)的語句從外到里地執(zhí)行,而不是當(dāng)成不相關(guān)語句從里到外執(zhí)行。讓mysql先執(zhí)行里面的查詢也是有辦法的,當(dāng)成臨時(shí)表來實(shí)現(xiàn),從而避免巨大的性能開銷。

mysql從臨時(shí)表來實(shí)現(xiàn)嵌套查詢(某種程度上被訛傳的衍生表)。這意味著mysql先執(zhí)行里面的查詢,并且把結(jié)果儲(chǔ)存在臨時(shí)表中,然后在其他的表里用到它。這就是我寫這個(gè)查詢時(shí)所期待的執(zhí)行方式。查詢語句修改如下:   
[sql]
復(fù)制代碼 代碼如下:

select * from subcategory 
where id in ( 
    select id from ( 
        select c.id 
        from subcategory as c 
            inner join item as i on i.subcategory = c.id 
        where c.category = 14 
        group by c.id 
        having count(*) > 2000 
    ) as x 
); 
 

我所做的就是把嵌套包著原來的嵌套查詢。mysql會(huì)認(rèn)為最里面是一個(gè)獨(dú)立的嵌套查詢先執(zhí)行,然后現(xiàn)在只剩下包著外面的嵌套,它已經(jīng)被裝進(jìn)一個(gè)臨時(shí)表里,只有少量記錄,因此要快很多。依此分析,這是相當(dāng)笨的優(yōu)化辦法;倒不如把它重寫成join方式。再說,免得被別人看到,當(dāng)成多余代碼清理掉。

有些情況可以使用這種優(yōu)化方法,比如mysql拋出錯(cuò)誤,嵌套查詢的表在其他地方被修改(譯注:另一篇文章 MySQL SELECT同時(shí)UPDATE同一張表 )。不幸的是,對(duì)于臨時(shí)表只能在查詢語句中使用一次的情況,這種方法就無能為力了。

來源  http://blog.csdn.net/afeiqiang/article/details/8620038

相關(guān)文章

  • mysql for update是鎖表還是鎖行實(shí)例詳解

    mysql for update是鎖表還是鎖行實(shí)例詳解

    在并發(fā)一致性控制場(chǎng)景中,我們常常用for update悲觀鎖來進(jìn)行一致性的保證,但是如果不了解它的機(jī)制,就進(jìn)行使用,很容易出現(xiàn)事故,比如for update進(jìn)行了鎖表導(dǎo)致其他請(qǐng)求只能等待,從而拖垮系統(tǒng),這篇文章主要介紹了mysql for update是鎖表還是鎖行操作,需要的朋友可以參考下
    2024-03-03
  • mysql_ssl_rsa_setup的具體使用

    mysql_ssl_rsa_setup的具體使用

    mysql_ssl_rsa_setup?是一個(gè)MySQL附帶的工具,用于自動(dòng)創(chuàng)建SSL證書和密鑰文件,本文主要介紹了mysql_ssl_rsa_setup的具體使用,感興趣的可以了解一下
    2024-07-07
  • Mysql數(shù)據(jù)庫(kù)按時(shí)間點(diǎn)恢復(fù)實(shí)戰(zhàn)記錄

    Mysql數(shù)據(jù)庫(kù)按時(shí)間點(diǎn)恢復(fù)實(shí)戰(zhàn)記錄

    如果客戶在某時(shí)間節(jié)點(diǎn)由于誤操作,導(dǎo)致數(shù)據(jù)丟失,RDS管控服務(wù)是如何進(jìn)行恢復(fù)的呢?通過Mysql數(shù)據(jù)庫(kù)按時(shí)間點(diǎn)恢復(fù)該如何操作呢,感興趣的朋友跟隨小編一起看看吧
    2021-06-06
  • mysql-8.0.11-winx64.zip安裝教程詳解

    mysql-8.0.11-winx64.zip安裝教程詳解

    這篇文章主要介紹了mysql-8.0.11-winx64.zip安裝教程詳解及注意事項(xiàng),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下
    2018-05-05
  • MySQL 8.0.13 下載安裝教程圖文詳解

    MySQL 8.0.13 下載安裝教程圖文詳解

    這篇文章主要介紹了MySQL 8.0.13 下載安裝教程,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-11-11
  • MySQL安裝后沒有my.ini配置文件的解決

    MySQL安裝后沒有my.ini配置文件的解決

    這篇文章主要介紹了MySQL安裝后沒有my.ini配置文件的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • mysql5.6 解析JSON字符串方式(支持復(fù)雜的嵌套格式)

    mysql5.6 解析JSON字符串方式(支持復(fù)雜的嵌套格式)

    這篇文章主要介紹了mysql5.6 解析JSON字符串方式(支持復(fù)雜的嵌套格式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • MySQL事務(wù)日志(redo?log和undo?log)的詳細(xì)分析

    MySQL事務(wù)日志(redo?log和undo?log)的詳細(xì)分析

    innodb事務(wù)日志包括redo?log和undo?log,redo?log是重做日志,提供前滾操作,undo?log是回滾日志,提供回滾操作,下面這篇文章主要給大家介紹了關(guān)于MySQL事務(wù)日志(redo?log和undo?log)的詳細(xì)分析,需要的朋友可以參考下
    2022-04-04
  • Mysql 數(shù)據(jù)庫(kù)中設(shè)備實(shí)時(shí)狀態(tài)表水平分表

    Mysql 數(shù)據(jù)庫(kù)中設(shè)備實(shí)時(shí)狀態(tài)表水平分表

    在使用 Mysql 數(shù)據(jù)庫(kù)存儲(chǔ)設(shè)備上報(bào)日志時(shí),存在一張?jiān)O(shè)備實(shí)時(shí)狀態(tài)表,隨著時(shí)間推移,數(shù)據(jù)量變得十分龐大,為了更好地管理和查詢數(shù)據(jù),提高數(shù)據(jù)庫(kù)性能,需要對(duì)該表進(jìn)行水平分表操作,下面就來介紹一下如何實(shí)現(xiàn)
    2025-06-06
  • MySQL觸發(fā)器的使用詳解

    MySQL觸發(fā)器的使用詳解

    觸發(fā)器trigger是一種特殊的存儲(chǔ)過程,他在插入(inset)、刪除(delete)或修改(update)特定表中的數(shù)據(jù)時(shí)觸發(fā)執(zhí)行,下面這篇文章主要給大家介紹了關(guān)于MySQL觸發(fā)器使用的相關(guān)資料,需要的朋友可以參考下
    2022-06-06

最新評(píng)論

康保县| 卫辉市| 蒙城县| 康定县| 凯里市| 密山市| 青海省| 五大连池市| 崇义县| 理塘县| 南京市| 汶上县| 灌云县| 东安县| 英德市| 莱州市| 青阳县| 龙口市| 中山市| 夏津县| 西贡区| 呼伦贝尔市| 安阳县| 江永县| 嘉兴市| 龙井市| 广昌县| 房产| 马鞍山市| 淳安县| 连山| 昭平县| 仁寿县| 大港区| 泰安市| 朔州市| 宁国市| 仙桃市| 柳州市| 乌兰察布市| 桐庐县|