mysql 关联表查询优化(3) - IN、EXISTS

IN、EXISTS 使用方式以及区别

数据背景

协议表数据.png

协议签署表数据.png

协议表数据总数为277811,协议签署表总数为541621 一看数据 协议签署表是协议表的两倍 就误以为使用EXISTS 性能会好一点但结果如何呢?下面的生产环境在跑的结果查询耗时20s, 不对呀 !为啥才几十万的数据为啥能查询时间这么长!难道是因为join 的表太多了导致时间太久?

原始协议查询sql.png

进一步查看改sql 的执行计划 居然执行了全表扫描,明明ps.signer_ent_id = '979425854629085184' 使用了索引字段查询按道理会走索引,但真实却没有。所以查询时间才这么久!

原始协议查询sql查询耗时.png
原始协议查询sql查询执行计划.png

原始sql 使用EXISTS

-- 原始sql  使用EXISTS
EXPLAIN SELECT
    ep.id,
    ep.expired_date AS expireDate,
    ep.create_id AS createId,
    ep.create_time AS createTime,
    ep.finish_time AS finishTime,
    ep.dead_time AS deadTime,
    ep.page_no AS pageNo,
    ep.protocol_code AS protocolCode,
    ep.buss_type AS bussType,
    ep.protocol_type AS protocolType,
    ep.contract_name AS contractName,
    ep.contract_no AS contractNo,
    ep.biz_id AS bizId,
    ep.biz_code AS bizCode,
    ep.sign_state AS signState,
    ep.remark AS remark,
    ep.is_sign AS isSign,
    ep.system_channel AS systemChannel,
    ep.fail_reason AS failReason,
    ep.download_state AS downloadState,
    ep.can_download AS canDownload,
    ep.file_temp_name AS fileTempName,
    ep.file_related_id AS fileRelatedId,
    ep.file_save_type AS fileSaveType,

IF (ep.file_save_type = 2, 1, 0) AS isBackup,
 ps1.signer_id AS signerAId,
 ps1.signer_ent_id AS signerAEntId,
 ps1.signer_name AS signerAName,
 ps1.sign_time AS signATime,
 ps1.signer_state AS signerAState,
 ps1.remark AS aRemark,
 ps2.signer_id AS signerBId,
 ps2.signer_ent_id AS signerBEntId,
 ps2.signer_name AS signerBName,
 ps2.sign_time AS signBTime,
 ps2.signer_state AS signerBState,
 ps2.remark AS bRemark,
 ps3.signer_id AS signerCId,
 ps3.signer_ent_id AS signerCEntId,
 ps3.signer_name AS signerCName,
 ps3.sign_time AS signCTime,
 ps3.signer_state AS signerCState,
 ps3.remark AS cRemark
FROM
    pub_enterprise_protocol ep
LEFT JOIN pub_enterprise_protocol_signer ps1 ON ps1.contract_no = ep.contract_no
AND ps1.signer_type = 'A'
LEFT JOIN pub_enterprise_protocol_signer ps2 ON ps2.contract_no = ep.contract_no
AND ps2.signer_type = 'B'
LEFT JOIN pub_enterprise_protocol_signer ps3 ON ps3.contract_no = ep.contract_no
AND ps3.signer_type = 'C'
WHERE
    1 = 1
AND EXISTS (
    SELECT
        1
    FROM
        pub_enterprise_protocol_signer ps
    WHERE
        ps.contract_no = ep.contract_no
    AND ps.signer_ent_id = '979425854629085184'
)
AND ep.protocol_type = '1'
LIMIT 0,
 100;

优化分析

当子查询结果集很大,而外部表较小的时候,查询效率会优于IN。
当子查询结果集较小,而外部表很大的时候,IN的查询效率会优于Exists。
改成in 看一下结果

优化后协议查询sql查询耗时.png
优化后协议查询sql查询执行计划.png

优化后sql 使用in

-- 优化后sql 使用in 
EXPLAIN SELECT
    ep.id,
    ep.expired_date AS expireDate,
    ep.create_id AS createId,
    ep.create_time AS createTime,
    ep.finish_time AS finishTime,
    ep.dead_time AS deadTime,
    ep.page_no AS pageNo,
    ep.protocol_code AS protocolCode,
    ep.buss_type AS bussType,
    ep.protocol_type AS protocolType,
    ep.contract_name AS contractName,
    ep.contract_no AS contractNo,
    ep.biz_id AS bizId,
    ep.biz_code AS bizCode,
    ep.sign_state AS signState,
    ep.remark AS remark,
    ep.is_sign AS isSign,
    ep.system_channel AS systemChannel,
    ep.fail_reason AS failReason,
    ep.download_state AS downloadState,
    ep.can_download AS canDownload,
    ep.file_temp_name AS fileTempName,
    ep.file_related_id AS fileRelatedId,
    ep.file_save_type AS fileSaveType,

IF (ep.file_save_type = 2, 1, 0) AS isBackup,
 ps1.signer_id AS signerAId,
 ps1.signer_ent_id AS signerAEntId,
 ps1.signer_name AS signerAName,
 ps1.sign_time AS signATime,
 ps1.signer_state AS signerAState,
 ps1.remark AS aRemark,
 ps2.signer_id AS signerBId,
 ps2.signer_ent_id AS signerBEntId,
 ps2.signer_name AS signerBName,
 ps2.sign_time AS signBTime,
 ps2.signer_state AS signerBState,
 ps2.remark AS bRemark,
 ps3.signer_id AS signerCId,
 ps3.signer_ent_id AS signerCEntId,
 ps3.signer_name AS signerCName,
 ps3.sign_time AS signCTime,
 ps3.signer_state AS signerCState,
 ps3.remark AS cRemark
FROM
    pub_enterprise_protocol ep
LEFT JOIN pub_enterprise_protocol_signer ps1 ON ps1.contract_no = ep.contract_no
AND ps1.signer_type = 'A'
LEFT JOIN pub_enterprise_protocol_signer ps2 ON ps2.contract_no = ep.contract_no
AND ps2.signer_type = 'B'
LEFT JOIN pub_enterprise_protocol_signer ps3 ON ps3.contract_no = ep.contract_no
AND ps3.signer_type = 'C'
WHERE
    ep.contract_no IN (
        SELECT
            ps.contract_no
        FROM
            pub_enterprise_protocol_signer ps
        WHERE
            ps.signer_ent_id = '979425854629085184'
    )
AND ep.protocol_type = '1'
LIMIT 0,
 100;

结果证明 改成in后查询时间只需0.019s 相比优化前20.57s 提升1085倍,并且查看了优化后的执行计划 条件命中索引 扫描的行数也只有32 行 相比原来277811 行全表扫描,可谓提升巨大

问题分析 EXISTS变慢了?

由EXISTS执行计划看到 子查询并没有走索引走的是where 接下来做个实验 去掉查询条件


原始协议查询不带条件执行计划.png

发现还是会全表扫描 但是子查询走了索引 索引字段是合同编号 查询时间也到了毫秒级别 这才是一个正常的查询时间(虽然和in 还有一倍的差距 但是也提升巨大)
子查询中 两个条件 (A)ps.contract_no = ep.contract_no(B)AND ps.signer_ent_id = '979425854629085184' 都是索引列为啥使用B 条件 反而没走索引了?
有执行计划中的子查询可知:
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询 ,DEPENDENT SUBQUERY , 那么就会先执行外部的查询 , 然后再循环执行内部的查询
MATERIALIZED: 子查询视图
EXISTS 的子查询出现 DEPENDENT SUBQUERY 先查询了外部表277811 行 在根据查询子查询条件 当只有A时走了contract_no索引字段 当同时出现B时 虽然执行计划上显示可能用到的索引字段是contract_no 但最终走了where 条件,这就说明了EXISTS 慢的原因

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容