美文网首页
单表查询和多表连接查询哪个效率更快

单表查询和多表连接查询哪个效率更快

作者: 一觉睡到丶小时候 | 来源:发表于2021-02-07 10:07 被阅读0次

    一.第一个解答来源于《高性能Mysql》中的回答

    很多高性能的应用都会对关联查询进行分解。简单地,可以对每个表进行一次单表查询,然后将结果在应用程序中进行关联。

    例如,下面这个查询:

    select * from tag
    
    join tag_post on tag_post.tag_id=tag.id
    
    join post on tag_post.post_id=post.id
    
    where tag.tag=’mysql’;
    
    可以分解成下面这些查询来代替:
    
    Select * from tag where tag=’mysql’;
    
    Select * from tag_post where tag_id=1234;
    
    Select * from post where id in(123,456,567,9989,8909);
    

    事实上,用分解关联查询的方式重构查询具有如下优势:(高并发、高性能的应用中,一般建议使用单表查询)

    1. 让缓存的效率更高。

    许多应用程序可以方便地缓存单表查询对应的结果对象。另外对于MySQL的查询缓存来说,如果关联中的某个表发生了变化,那么就无法使用查询缓存了,而拆分后,如果某个表很少改变,那么基于该表的查询就可以重复利用查询缓存结果了。

    1. 将查询分解后,执行单个查询可以减少锁的竞争。

    2. 在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能和可扩展。

    3. 查询本身效率也可能会有所提升。

    4. 可以减少冗余记录的查询。

    5. 更进一步,这样做相当于在应用中实现了哈希关联,而不是使用MySQL的嵌套环关联,某些场景哈希关联的效率更高很多。

    6. 单表查询有利于后期数据量大了分库分表,如果联合查询的话,一旦分库,原来的sql都需要改动。

    7. 上次看到某个CTO技术分享,公司规定底层禁止用join联合查询。数据大的时候确实慢。

    8. 联合查询或许确实快,但是mysql的资源通常比程序代码的资源紧张的多。

    二.单表多次查询和多表联合查询效果对比

    在同等条件下,以用户、角色、及用户角色关联表为例。

    select * from sys_user where user_name='admin';
    select * from sys_user_role where user_id ='1';
    select * from sys_role where role_id ='1';
    
    select * from sys_user su LEFT JOIN sys_user_role sur ON su.user_id = sur.user_id
    LEFT JOIN sys_role sr ON sur.role_id = sr.role_id
    where user_name='admin';
    
    >>>>>>>>>
    [SQL]select * from sys_user where user_name='admin';
    受影响的行: 0
    时间: 0.004s
    
    [SQL]
    select * from sys_user_role where user_id ='1';
    受影响的行: 0
    时间: 0.002s
    
    [SQL]
    select * from sys_role where role_id ='1';
    受影响的行: 0
    时间: 0.004s
    
    [SQL]
    
    select * from sys_user su LEFT JOIN sys_user_role sur ON su.user_id = sur.user_id
    LEFT JOIN sys_role sr ON sur.role_id = sr.role_id
    where user_name='admin';
    受影响的行: 0
    时间: 0.001s
    

    查询包装单位

    select unit_name from erp_unit where unit_id=1;
    select unit_name from erp_unit where unit_id=2;
    select unit_name from erp_unit where unit_id=3;
    
    SELECT 
            eus.unit_name AS smallName, 
            eum.unit_name AS middleName, 
            eub.unit_name AS bigName 
            FROM 
            erp_goods_detail egd 
            LEFT JOIN erp_unit eus ON egd.small_unit_id = eus.unit_id 
            LEFT JOIN erp_unit eum ON egd.middle_unit_id = eum.unit_id 
            LEFT JOIN erp_unit eub ON egd.big_unit_id = eub.unit_id 
            WHERE 
            egd.goods_id = '1357597885043163138';
    
    >>>>>>>>>>>>>>>>>>>>>
    [SQL]select unit_name from erp_unit where unit_id=1;
    受影响的行: 0
    时间: 0.002s
    
    [SQL]
    select unit_name from erp_unit where unit_id=2;
    受影响的行: 0
    时间: 0.002s
    
    [SQL]
    select unit_name from erp_unit where unit_id=3;
    受影响的行: 0
    时间: 0.002s
    
    [SQL]
    
    SELECT 
            eus.unit_name AS smallName, 
            eum.unit_name AS middleName, 
            eub.unit_name AS bigName 
            FROM 
            erp_goods_detail egd 
            LEFT JOIN erp_unit eus ON egd.small_unit_id = eus.unit_id 
            LEFT JOIN erp_unit eum ON egd.middle_unit_id = eum.unit_id 
            LEFT JOIN erp_unit eub ON egd.big_unit_id = eub.unit_id 
            WHERE 
            egd.goods_id = '1357597885043163138';
    受影响的行: 0
    时间: 0.002s
    

    看一下代码中的运行时间

    @Service
    public class AServiceImpl implements AService {
    
        @Autowired
        private UnitMapper unitMapper;
    
        @Override
        public void testA() {
            singleSearch();
            allSearch();
        }
    
        private void singleSearch() {
            Long start = System.currentTimeMillis();
            for (int i = 0; i < 10; i++) {
                unitMapper.selectNameByUnitId((long) 1);
                unitMapper.selectNameByUnitId((long) 2);
                unitMapper.selectNameByUnitId((long) 3);
            }
            Long end = System.currentTimeMillis();
            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>" + (end - start));
        }
    
        private void allSearch() {
            Long start = System.currentTimeMillis();
            for (int i = 0; i < 10; i++) {
                unitMapper.searchAll();
            }
            Long end = System.currentTimeMillis();
            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>" + (end - start));
        }
    }
    

    singleSearch方法的总耗时4533,allSearch方法的总耗时1378

    在遍历中每个查询方法的用时对比
    singleSearch(单位ms):[4、4、3、4、4、3、5、3、3、4、3、7、4、5、19、4、4、3、3、3、4、4、11、4、5、4、4、4、3、220]

    allSearch(单位ms):[5、4、4、4、5、4、4、4、5、9]

    还是上边的方法,我们将遍历次数调整到1000

    @Service
    public class AServiceImpl implements AService {
    
        @Autowired
        private UnitMapper unitMapper;
    
        @Override
        public Map<String, Long> testA() {
            Long single = singleSearch();
            Long all = allSearch();
            Map map = new HashMap();
            map.put("single", single);
            map.put("all", all);
            return map;
        }
    
        private Long singleSearch() {
            Long start = System.currentTimeMillis();
            for (int i = 0; i < 1000; i++) {
                unitMapper.selectNameByUnitId((long) 1);
                unitMapper.selectNameByUnitId((long) 2);
                unitMapper.selectNameByUnitId((long) 3);
            }
            Long end = System.currentTimeMillis();
            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>" + (end - start));
            return end - start;
        }
    
        private Long allSearch() {
            Long start = System.currentTimeMillis();
            for (int i = 0; i < 1000; i++) {
                unitMapper.searchAll();
            }
            Long end = System.currentTimeMillis();
            System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>" + (end - start));
            return end - start;
        }
    }
    

    输出结果

    {"code":200,"success":true,"data":{"single":362416,"all":7388},"msg":"操作成功"}
    

    相关文章

      网友评论

          本文标题:单表查询和多表连接查询哪个效率更快

          本文链接:https://www.haomeiwen.com/subject/jdaatltx.html