共計(jì) 12706 個(gè)字符,預(yù)計(jì)需要花費(fèi) 32 分鐘才能閱讀完成。
自動(dòng)寫代碼機(jī)器人,免費(fèi)開通
這篇文章主要介紹 SQL 如何優(yōu)化,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
一、存在問題
經(jīng)過 sql 慢查詢的優(yōu)化,我們系統(tǒng)中發(fā)現(xiàn)了以下幾種類型的問題:
1. 未建索引:整張表沒有建索引;2. 索引未命中:有索引, 但是部分查詢條件下索引未命中;3. 搜索了額外的非必要字段,導(dǎo)致回表;4. 排序,聚合導(dǎo)致慢查詢;5. 相同內(nèi)容多次查詢數(shù)據(jù)庫;6. 未消限制搜索范圍或者限制的搜索范圍在預(yù)期之外,導(dǎo)致全部掃描;
二、解決方案
1. 優(yōu)化索引,增加或者修改當(dāng)前的索引;
2. 重寫 sql;3. 利用 redis 緩存,減少查詢次數(shù);4. 增加條件,避免非必要查詢;5. 增加條件,減少查詢范圍;
三、案例分析
(一)藥材搜索接口
完整 sql 語句在附錄,為方便閱讀和脫敏,部分常用字段采用中文。
這兒主要講一下我們拿到 Sql 語句后的整個(gè)分析過程,思考邏輯,然后進(jìn)行調(diào)整的過程和最后解決的辦法。
給大家提供一些借鑒,也希望大家能夠提出更好的建議。
這個(gè) sql 語句要求是根據(jù)醫(yī)生搜索的拼音或者中文,進(jìn)行模糊查詢,找到藥材,然后根據(jù)醫(yī)生選擇的藥庫,查找下面的供應(yīng)商,然后根據(jù)供應(yīng)商,進(jìn)行藥材匹配,排除掉供應(yīng)商沒有的藥材,然后根據(jù)真名在前,別名在后,完全匹配在前,部分匹配在后,附加醫(yī)生最近半年的使用習(xí)慣,把藥材排序出來。最后把不同名稱的同一味藥聚合起來,以真名 (另名) 的形式展現(xiàn)。
1.分析 sql
(1)14-8
第 14 排,id 為 8 的 explain 結(jié)果分析:
①Explain
8,DERIVED,ssof,range, ix_district,ix_供應(yīng)商 id ,ix_district,8,NULL,18,Using where; Using index; Using temporary
②Sql
SELECT DISTINCT (ssof. 供應(yīng)商 id) AS 供應(yīng)商 id FROM 藥庫供應(yīng)商關(guān)系表 AS ssof WHERE ssof. 藥庫 id IN ( 1, 2, 8, 9, 10, 11, 12, 13, 14, 15, 17, 22, 24, 25, 26, 27, 31, 33) AND ssof. 藥方劑型 id IN (1)
③索引
PRIMARY KEY (`id`), UNIQUE KEY `ix_district` ( ` 藥庫 id`, ` 藥方劑型 id`, ` 供應(yīng)商 id` ) USING BTREE,KEY `ix_供應(yīng)商 id` (` 供應(yīng)商 id`) USING BTREE
④分析
使用了索引,建立了臨時(shí)表,這個(gè)地方索引已經(jīng)完全覆蓋了,但是還有回表操作。
原因是用 in,這個(gè)導(dǎo)致了回表。如果 in 可以被 mysql 自動(dòng)優(yōu)化為等于,就不會(huì)回表。如果無法優(yōu)化,就回表。
臨時(shí)表是因?yàn)橛?distinct,所以無法避免。
同時(shí)使用 in 需要注意,如果里面的值數(shù)量比較多,有幾萬個(gè)。即使區(qū)分度高,就會(huì)導(dǎo)致索引失效,這種情況需要多次分批查詢。
2. 12-7
(1)Explain
7,DERIVED, derived8 ,ALL,NULL,NULL,NULL,NULL,18,Using temporary; Using filesort
(2)Sql
INNER JOIN (上面 14- 8 臨時(shí)表) tp ON tp. 供應(yīng)商 id= ms. 供應(yīng)商 id
(3)索引
無
(4)分析
對(duì)臨時(shí)表操作,無索引,用了文件排序。
這一部分是對(duì)臨時(shí)表和藥材表進(jìn)行關(guān)聯(lián)操作的一部分,有文件排序是因?yàn)樾枰獙?duì)藥材表 id 進(jìn)行 group by 導(dǎo)致的。
1、默認(rèn)情況下,mysql 在使用 group by 之后,會(huì)產(chǎn)生臨時(shí)表,而后進(jìn)行排序(此處排序默認(rèn)是快排),這會(huì)消耗的性能。
2、group by 本質(zhì)是先分組后排序【而不是先排序后分組】。
3、group by column 默認(rèn)會(huì)按照 column 分組, 然后根據(jù) column 升序排列; group by column order by null 則默認(rèn)按照 column 分組, 然后根據(jù)標(biāo)的主鍵 ID 升序排列。
3. 13-7
(1)Explain
7,DERIVED,ms,ref, ix_title,idx_audit,idx_mutiy ,idx_mutiy,5, tp. 供應(yīng)商 id,const ,172,NULL
(2)Sql
SELECT ms. 藥材表 id, max(ms.audit) AS audit, max(ms.price) AS price, max(ms.market_price) AS market_price,max(ms.is_granule) AS is_granule,max(ms.is_decoct) AS is_decoct, max(ms.is_slice) AS is_slice,max(ms.is_cream) AS is_cream, max(ms.is_extract) AS is_extract,max(ms.is_cream_granule) AS is_cream_granule, max(ms.is_extract_granule) AS is_extract_granule,max(ms.is_drychip) AS is_drychip, max(ms.is_pill) AS is_pill,max(ms.is_powder) AS is_powder, max(ms.is_bolus) AS is_bolus FROM 供應(yīng)商藥材表 AS ms INNER JOIN ( SELECT DISTINCT (ssof. 供應(yīng)商 id) AS 供應(yīng)商 id FROM 藥庫供應(yīng)商關(guān)系表 AS ssof WHERE ssof. 藥庫 id IN ( 1, 2, 8, 9, 10, 11, 12, 13, 14, 15, 17, 22, 24, 25, 26, 27, 31, 33 ) AND ssof. 藥方劑型 id IN (1) ) tp ON tp. 供應(yīng)商 id= ms. 供應(yīng)商 id WHERE ms.audit = 1 GROUP BY ms. 藥材表 id
(3)索引
KEY `idx_mutiy` (` 供應(yīng)商 id`, `audit`, ` 藥材表 id`)
(4)分析
命中了索引,表間連接使用了供應(yīng)商 id,建立索引的順序是供應(yīng)商 id,where 條件中 audit,Group by 條件藥材表 id。
這部分暫時(shí)不需要更改。
4.10-6
(1)Explain
6,DERIVED,r,range, PRIMARY,id,idx_timeline,idx_did_timeline,idx_did_isdel_statuspay_timecreate_payorderid,idx_did_statuspay_ischecked_isdel ,idx_did_timeline,8,NULL,546,Using where; Using index; Using temporary; Using filesort
(2)Sql
SELECT
count(*) AS total,
rc.i AS m 藥材表 id
FROM
處方藥材表 AS rc
INNER JOIN 藥方表 AS r ON r.id = rc. 藥方表_id
WHERE
r.did = 40
AND r.timeline 1576115196
AND rc.type_id in (1, 3)
GROUP BY
rc.i
(3)索引
KEY `idx_did_timeline` (`did`, `timeline`),
(4)分析
驅(qū)動(dòng)表與被驅(qū)動(dòng)表,小表驅(qū)動(dòng)大表。
先了解在 join 連接時(shí)哪個(gè)表是驅(qū)動(dòng)表,哪個(gè)表是被驅(qū)動(dòng)表:
1. 當(dāng)使用 left join 時(shí),左表是驅(qū)動(dòng)表,右表是被驅(qū)動(dòng)表;
2. 當(dāng)使用 right join 時(shí),右表時(shí)驅(qū)動(dòng)表,左表是驅(qū)動(dòng)表;
3. 當(dāng)使用 join 時(shí),mysql 會(huì)選擇數(shù)據(jù)量比較小的表作為驅(qū)動(dòng)表,大表作為被驅(qū)動(dòng)表;
4. in 后面跟的是驅(qū)動(dòng)表, exists 前面的是驅(qū)動(dòng)表;
5. 11-6
(1)Explain
6,DERIVED,rc,ref, orderid_藥材表, 藥方表_id , 藥方表_id,5,r.id,3,Using where
(2)Sql
同上
(3)索引
KEY `idx_藥方表_id` (` 藥方表_id`, `type_id`) USING BTREE,
(4)分析
索引的順序沒有問題,仍舊是 in 導(dǎo)致了回表。
6.8-5
(1)Explain
5,UNION,malias,ALL,id_tid,NULL,NULL,NULL,4978,Using where
(2)Sql
SELECT
mb.id,
mb.sort_id,
mb.title,
mb.py,
mb.unit,
mb.weight,
mb.tid,
mb.amount_max,
mb.poisonous,
mb.is_auxiliary,
mb.is_auxiliary_free,
mb.is_difficult_powder,
mb.brief,
mb.is_fixed_recipe,
ASE WHEN malias.py = GC THEN malias.title ELSE CASE WHEN malias.title = GC THEN malias.title ELSE END END AS atitle,
alias.py AS apy,
CASE WHEN malias.py = GC THEN 2 ELSE CASE WHEN malias.title = GC THEN 2 ELSE 1 END END AS ttid
FROM
藥材表 AS mb
LEFT JOIN 藥材表 AS malias ON malias.tid = mb.id
WHERE
alias.title LIKE %GC%
OR malias.py LIKE %GC%
(3)索引
KEY `id_tid` (`tid`) USING BTREE,
(4)分析
因?yàn)?like 是左右 like,無法建立索引,所以只能建 tid。Type 是 all,遍歷全表以找到匹配的行,左右表大小一樣,估算的找到所需的記錄所需要讀取的行數(shù)有 4978。這個(gè)因?yàn)槭?like 的緣故,無法優(yōu)化,這個(gè)語句并沒有走索引,藥材表 AS mb FORCE INDEX (id_tid) 改為強(qiáng)制索引,讀取的行數(shù)減少了 700 行。
7.9-5
(1)Explain
5,UNION,mb,eq_ref, PRIMARY,ix_id ,PRIMARY,4,malias.tid,1,NULL
(2)Sql
同上
(3)索引
PRIMARY KEY (`id`) USING BTREE,
(4)分析
走了主鍵索引,行數(shù)也少,通過。
8.7-4
(1)Explain
4,DERIVED,mb,ALL,id_tid,NULL,NULL,NULL,4978,Using where
(2)Sql
SELECT
mb.id,
mb.sort_id,
mb.title,
mb.py,
mb.unit,
mb.weight,
mb.tid,
mb.amount_max,
mb.poisonous,
mb.is_auxiliary,
mb.is_auxiliary_free,
mb.is_difficult_powder,
mb.brief,
mb.is_fixed_recipe,
AS atitle,
AS apy,
CASE WHEN mb.py = GC THEN 3 ELSE CASE WHEN mb.title = GC THEN 3 ELSE 1 END END AS ttid
FROM
藥材表 AS mb
WHERE
mb.tid = 0
AND (
mb.title LIKE %GC%
OR mb.py LIKE %GC%
)
(3)索引
KEY `id_tid` (`tid`) USING BTREE,
(4)分析
tid int(11) NOT NULL DEFAULT‘0’COMMENT‘真名藥品的 id’,
他也是 like, 這個(gè)沒法優(yōu)化。
9.6-3
(1)Explain
3,DERIVED, derived4 ,ALL,NULL,NULL,NULL,NULL,9154,Using filesort
(2)Sql
UNION ALL
(3)索引
無
(4)分析
就是把真名搜索結(jié)果和別人搜索結(jié)果合并。避免用 or 連接,加快速度 形成一個(gè) munion 的表,初步完成藥材搜索,接下去就是排序。
這一個(gè)進(jìn)行了 2 次查詢,然后用 union 連接,可以考慮合并為一次查詢。用 case when 進(jìn)行區(qū)分, 計(jì)算出權(quán)重。
這邊是一個(gè)優(yōu)化點(diǎn)。
10.4-2
(1)Explain
2,DERIVED, derived3 ,ALL,NULL,NULL,NULL,NULL,9154,NULL
(2)Sql
SELECT
munion.id,
munion.sort_id,
case when length(
trim( group_concat(munion.atitle SEPARATOR )
)
) 0 then concat(
munion.title,
( ,
trim( group_concat(munion.atitle SEPARATOR )
),
)
) else munion.title end as title,
munion.py,
munion.unit,
munion.weight,
munion.tid,
munion.amount_max,
munion.poisonous,
munion.is_auxiliary,
munion.is_auxiliary_free,
munion.is_difficult_powder,
munion.brief,
munion.is_fixed_recipe,
-- trim( group_concat( munion.atitle SEPARATOR ) ) AS atitle,
## --
trim( group_concat(munion.apy SEPARATOR )
) AS apy,
##
max(ttid) * 100000 + id AS ttid
FROM
munion derived4
GROUP BY
id -- 全部實(shí)名藥材 結(jié)束 ##
(3)索引
無
(4)分析
這里全部在臨時(shí)表中搜索了。
11.5-2
(1)Explain
2,DERIVED, derived6 ,ref, auto_key0 , auto_key0 ,5,m.id,10,NULL
(2)Sql
Select fields from 全部實(shí)名藥材表 as m LEFT JOIN ( 個(gè)人使用藥材統(tǒng)計(jì)表 ) p ON m.id = p.m 藥材表 id
(3)索引
無
(4)分析
2 張?zhí)摂M表 left join
使用了優(yōu)化器為派生表生成的索引
這邊比較浪費(fèi)性能,每次查詢,都要對(duì)醫(yī)生歷史開方記錄進(jìn)行統(tǒng)計(jì),并且統(tǒng)計(jì)還是幾張大表計(jì)算后的結(jié)果。但是如果只是 sql 優(yōu)化,這邊暫時(shí)無法優(yōu)化。
12.2-1
(1)Explain
1,PRIMARY, derived7 ,ALL,NULL,NULL,NULL,NULL,3096,Using where; Using temporary; Using filesort
(2)Sql
(3)索引
(4)分析
臨時(shí)表操作
13.3-1
(1)Explain
1,PRIMARY, derived2 ,ref, auto_key0 , auto_key0 ,4,msu. 藥材表 id,29,NULL
(2)Sql
(3)索引
(4)分析
臨時(shí)表操作
14.null
(1)Explain
NULL,UNION RESULT, union4,5 ,ALL,NULL,NULL,NULL,NULL,NULL,Using temporary
(2)Sql
(3)索引
(4)分析
臨時(shí)表
(二)優(yōu)化 sql
上面我們只做索引的優(yōu)化, 遵循的原則是:
1. 最左前綴匹配原則,非常重要的原則,mysql 會(huì)一直向右匹配直到遇到范圍查詢 (、、between、like) 就停止匹配,比如 a = 1 and b = 2 and c 3 and d = 4 如果建立 (a,b,c,d) 順序的索引,d 是用不到索引的,如果建立 (a,b,d,c) 的索引則都可以用到,a,b,d 的順序可以任意調(diào)整。2.= 和 in 可以亂序,比如 a = 1 and b = 2 and c = 3 建立 (a,b,c) 索引可以任意順序,mysql 的查詢優(yōu)化器會(huì)幫你優(yōu)化成索引可以識(shí)別的形式。3. 盡量選擇區(qū)分度高的列作為索引,區(qū)分度的公式是 count(distinct col)/count(*),表示字段不重復(fù)的比例,比例越大我們掃描的記錄數(shù)越少,唯一鍵的區(qū)分度是 1,而一些狀態(tài)、性別字段可能在大數(shù)據(jù)面前區(qū)分度就是 0,那可能有人會(huì)問,這個(gè)比例有什么經(jīng)驗(yàn)值嗎?使用場景不同,這個(gè)值也很難確定,一般需要 join 的字段我們都要求是 0.1 以上,即平均 1 條掃描 10 條記錄。4. 索引列不能參與計(jì)算,保持列“干凈”,比如 from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很簡單,b+ 樹中存的都是數(shù)據(jù)表中的字段值,但進(jìn)行檢索時(shí),需要把所有元素都應(yīng)用函數(shù)才能比較,顯然成本太大。所以語句應(yīng)該寫成 create_time = unix_timestamp(’2014-05-29’)。5. 盡量的擴(kuò)展索引,不要新建索引。比如表中已經(jīng)有 a 的索引,現(xiàn)在要加 (a,b) 的索引,那么只需要修改原來的索引即可。
查詢優(yōu)化神器 – explain 命令
關(guān)于 explain 命令相信大家并不陌生,具體用法和字段含義可以參考官網(wǎng) explain-output,這里需要強(qiáng)調(diào) rows 是核心指標(biāo),絕大部分 rows 小的語句執(zhí)行一定很快(有例外,下面會(huì)講到)。所以優(yōu)化語句基本上都是在優(yōu)化 rows。
化基本步驟:
0. 先運(yùn)行看看是否真的很慢,注意設(shè)置 SQL_NO_CACHE1.where 條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的 where 都應(yīng)用到表中返回的記錄數(shù)最小的表開始查起,單表每個(gè)字段分別查詢,看哪個(gè)字段的區(qū)分度最高;2.explain 查看執(zhí)行計(jì)劃,是否與 1 預(yù)期一致(從鎖定記錄較少的表開始查詢);3.order by limit 形式的 sql 語句讓排序的表優(yōu)先查;4. 了解業(yè)務(wù)方使用場景;5. 加索引時(shí)參照建索引的幾大原則;6. 觀察結(jié)果,不符合預(yù)期繼續(xù)從 0 分析;
上面已經(jīng)詳細(xì)的分析了每一個(gè)步驟,根據(jù)上面的 sql,去除 union 操作,增加索引??梢钥闯?,優(yōu)化后雖然有所改善。但是距離我們的希望還有很大距離,但是光做 sql 優(yōu)化,感覺也沒有多少改進(jìn)空間, 所以決定從其他方面解決。
(三)拆分 sql
由于速度還是不領(lǐng)人滿意, 尤其是個(gè)人用藥情況統(tǒng)計(jì), 其實(shí)沒必要每次都全部統(tǒng)計(jì)一次, 再要優(yōu)化, 只靠修改索引應(yīng)該是不行的了, 所以考慮使用緩存。
接下來是修改 php 代碼, 把全部 sql 語句拆分, 然后再組裝。
(1)搜索真名, 別名(緩存)
SELECT mb.id, mb.sort_id, mb.title, mb.py, mb.unit, mb.weight, mb.tid, mb.amount_max, mb.poisonous, mb.is_auxiliary, mb.is_auxiliary_free, mb.is_difficult_powder, mb.brief, mb.is_fixed_recipe, IFNULL(group_concat(malias.title), ) atitle, IFNULL(group_concat(malias.py), ) apy FROM 藥材表 AS mb LEFT JOIN 藥材表 AS malias ON malias.tid = mb.id WHERE mb.tid = 0 AND ( malias.title LIKE %GC% OR malias.py LIKE %GC% or mb.title LIKE %GC% OR mb.py LIKE %GC% ) group by mb.id
(2)如果命中有藥材
①排序
真名在前, 別名在后, 完全匹配在前, 部分匹配在后
// 對(duì)搜索結(jié)果進(jìn)行處理, 增加權(quán)重
②對(duì)供應(yīng)商藥材搜索
SELECT ms. 藥材表 id, max( ms.audit ) AS audit, max( ms.price ) AS price, max( ms.market_price ) AS market_price, max( ms.is_granule ) AS is_granule, max( ms.is_decoct ) AS is_decoct, max( ms.is_slice ) AS is_slice, max( ms.is_cream ) AS is_cream, max( ms.is_extract ) AS is_extract, max( ms.is_cream_granule) AS is_cream_granule, max( ms.is_extract_granule) AS is_extract_granule, max( ms.is_drychip ) AS is_drychip, max( ms.is_pill ) AS is_pill, max( ms.is_powder ) AS is_powder, max( ms.is_bolus ) AS is_bolus FROM 供應(yīng)商藥材表 AS ms WHERE ms.audit = 1 AND ms. 供應(yīng)商 idin ( SELECT DISTINCT ( ssof. 供應(yīng)商 id) AS 供應(yīng)商 id FROM 藥庫供應(yīng)商關(guān)系表 AS ssof WHERE ssof. 藥庫 id IN ( 1,2,8,9,10,11,12,13,14,15,17,22,24,25,26,27,31,33 ) AND ssof. 藥方劑型 id IN (1) ) AND ms. 藥材表 id IN ( 78,205,206,207,208,209,334,356,397,416,584,652,988,3001,3200,3248,3521,3522,3599,3610,3624,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,5704,5705,5706,5739,5740,5741,5742,5743,6265,6266,6267,6268,6514,6515,6516,6517,6518,6742,6743 ) AND ms.is_slice = 1 GROUP BY ms. 藥材表 id
③拿醫(yī)生歷史開方藥材用量數(shù)據(jù)(緩存)
SELECT count( * ) AS total, rc.i AS 藥材表 id FROM 處方藥材表 AS rc INNER JOIN 藥方表 AS r ON r.id = rc. 藥方表_id WHERE r.did = 40 AND r.timeline 1576116927 AND rc.type_id in (1,3) GROUP BY rc.i
④ 裝配及排序微調(diào)
(3)小結(jié)
運(yùn)行速度, 對(duì)于開方量不是特別多的醫(yī)生來說, 兩者速度都是 0.1 秒左右. 但是如果碰到開方量大的醫(yī)生, 優(yōu)化后的 sql 速度比較穩(wěn)定, 能始終維持在 0.1 秒左右, 優(yōu)化前的 sql 速度會(huì)超過 0.2 秒. 速度提升約一倍以上。
最后對(duì)搜索結(jié)果和未優(yōu)化前的搜索結(jié)果進(jìn)行比對(duì), 結(jié)果數(shù)量和順序完全一致. 本次優(yōu)化結(jié)束。
四、附錄:
SELECT sql_no_cache
*FROM
(
-- mbu start## SELECT
m.*,
ifnull(p.total, 0) AS total FROM
(
-- 全部實(shí)名藥材
##SELECT
munion.id,
munion.sort_id,
case when length(
trim( group_concat(munion.atitle SEPARATOR )
)
) 0 then concat(
munion.title,
( ,
trim( group_concat(munion.atitle SEPARATOR )
),
)
) else munion.title end as title,
munion.py,
munion.unit,
munion.weight,
munion.tid,
munion.amount_max,
munion.poisonous,
munion.is_auxiliary,
munion.is_auxiliary_free,
munion.is_difficult_powder,
munion.brief,
munion.is_fixed_recipe,
-- trim( group_concat( munion.atitle SEPARATOR ) ) AS atitle,## -- trim( group_concat( munion.apy SEPARATOR ) ) AS apy,## max(ttid) * 100000 + id AS ttid FROM
(
-- #union start
聯(lián)合查找, 得到全部藥材
## (
SELECT
mb.id,
mb.sort_id,
mb.title,
mb.py,
mb.unit,
mb.weight,
mb.tid,
mb.amount_max,
mb.poisonous,
mb.is_auxiliary,
mb.is_auxiliary_free,
mb.is_difficult_powder,
mb.brief,
mb.is_fixed_recipe,
AS atitle,
AS apy,
CASE WHEN mb.py = GC THEN 3 ELSE CASE WHEN mb.title = GC THEN 3 ELSE 1 END END AS ttid FROM
藥材表 AS mb WHERE
mb.tid = 0
AND (
mb.title LIKE %GC%
OR mb.py LIKE %GC%
)
) -- 真名藥材
## UNION ALL
(
SELECT
mb.id,
mb.sort_id,
mb.title,
mb.py,
mb.unit,
mb.weight,
mb.tid,
mb.amount_max,
mb.poisonous,
mb.is_auxiliary,
mb.is_auxiliary_free,
mb.is_difficult_powder,
mb.brief,
mb.is_fixed_recipe,
CASE WHEN malias.py = GC THEN malias.title ELSE CASE WHEN malias.title = GC THEN malias.title ELSE END END AS atitle,
malias.py AS apy,
CASE WHEN malias.py = GC THEN 2 ELSE CASE WHEN malias.title = GC THEN 2 ELSE 1 END END AS ttid FROM
藥材表 AS mb LEFT JOIN 藥材表 AS malias ON malias.tid = mb.id WHERE
malias.title LIKE %GC%
OR malias.py LIKE %GC%
) -- 其他藥材結(jié)束
## -- #union end## ) munion GROUP BY
id -- 全部實(shí)名藥材
## ) m LEFT JOIN (
-- 個(gè)人使用藥材統(tǒng)計(jì)
## SELECT
count(*) AS total,
rc.i AS m 藥材表 id FROM
處方藥材表 AS rc INNER JOIN 藥方表 AS r ON r.id = rc. 藥方表_id WHERE
r.did = 40
AND r.timeline 1576115196
AND rc.type_id in (1, 3)
GROUP BY
rc.i -- 個(gè)人使用藥材統(tǒng)計(jì)
## ) p ON m.id = p.m 藥材表 id -- mbu end ## ) mbu INNER JOIN (
-- msu start
供應(yīng)商藥材篩選
## SELECT
ms. 藥材表 id,
max(ms.audit) AS audit,
max(ms.price) AS price,
max(ms.market_price) AS market_price,
max(ms.is_granule) AS is_granule,
max(ms.is_decoct) AS is_decoct,
max(ms.is_slice) AS is_slice,
max(ms.is_cream) AS is_cream,
max(ms.is_extract) AS is_extract,
max(ms.is_cream_granule) AS is_cream_granule,
max(ms.is_extract_granule) AS is_extract_granule,
max(ms.is_drychip) AS is_drychip,
max(ms.is_pill) AS is_pill,
max(ms.is_powder) AS is_powder,
max(ms.is_bolus) AS is_bolus FROM
供應(yīng)商藥材表 AS ms INNER JOIN (
SELECT
DISTINCT (ssof. 供應(yīng)商 id) AS 供應(yīng)商 id FROM
藥庫供應(yīng)商關(guān)系表 AS ssof WHERE
ssof. 藥庫 id IN (
1, 2, 8, 9, 10, 11, 12, 13, 14, 15, 17, 22,
24, 25, 26, 27, 31, 33
)
AND ssof. 藥方劑型 id IN (1)
) tp ON tp. 供應(yīng)商 id= ms. 供應(yīng)商 id WHERE
ms.audit = 1
GROUP BY
ms. 藥材表 id -- msu end ## ) msu ON mbu.id = msu. 藥材表 idWHERE
msu. 藥材表 id 0
AND msu.is_slice = 1order by
total desc,
ttid desc
以上是“SQL 如何優(yōu)化”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注丸趣 TV 行業(yè)資訊頻道!
向 AI 問一下細(xì)節(jié)