<cite id="pbjvp"></cite>

        <menuitem id="pbjvp"><em id="pbjvp"></em></menuitem>
        <ins id="pbjvp"></ins>

        <ins id="pbjvp"><video id="pbjvp"><mark id="pbjvp"></mark></video></ins>
        
        

        <output id="pbjvp"><em id="pbjvp"><b id="pbjvp"></b></em></output>

              <i id="pbjvp"><video id="pbjvp"><b id="pbjvp"></b></video></i>
              <mark id="pbjvp"></mark>
              <b id="pbjvp"><em id="pbjvp"><mark id="pbjvp"></mark></em></b>

              Jquery中文网 www.myllop.cn
              Jquery中文网 >  数据库  >  mysql  >  正文 Mysql 多表联合查询效率分析及优化

              Mysql 多表联合查询效率分析及优化

              发布时间:2017-12-13   编辑:www.myllop.cn
              jquery中文网为您提供Mysql 多表联合查询效率分析及优化等资源,欢迎您收藏本站,我们将为您提供最新的Mysql 多表联合查询效率分析及优化资源
              mysql大数据查询优化对于许多站长来讲都不会仔细的去分析了,对于这个问题小编最近碰到一个100W数据优化问题了,下面整理了一些mysql关联查询优化的测试及相关分析希望对各位有帮助。

              一,简单的关联子查询的一种优化 .

              很多时候,在mysql上实现的子查询的性能较差,这听起来实在有点难过。特别有时候,用到IN()子查询语句时,对于上了某种数量级的表来说,耗时多的难以估计。本人mysql知识所涉不深,只能慢慢摸透个中玄机了。


              假设有这样的一个exists查询语句:


              select * from table1
              where exists
                  (select * from table2 where id>=30000 and table1.uuid=table2.uuid);


              table1为十万行级的表,table2为百万行级的表,本机测试结果用时2.40s。


              通过explain可以看到子查询是一个相关子查询(DEPENDENCE SUBQUERY); Mysql会首先对外表table1进行全表扫描,然后根据返回的uuid逐次执行子查询。如果外层表是一个很大的表,我们可以想象查询性能会表现得比此次测试更糟糕。


              一种简单的优化方案为使用inner join的方法来代替子查询, 查询语句则可以改为:


              select * from table1 innner join table2 using(uuid) where table2.id>=30000;


              本机测试结果用时0.68s。


              通过explain可以看到mysql使用了SIMPLE类型(子查询或union以外的查询方式); Mysql优化器会先过滤table2,然后对table1和table2做笛卡尔积得出结果集后,再通过on条件来过滤数据。

              二、多表联合查询效率分析及优化


              1. 多表连接类型
              1. 笛卡尔积(交叉连接) 在MySQL中可以为CROSS JOIN或者省略CROSS即JOIN,或者使用','  如:


              01.SELECT * FROM table1 CROSS JOIN table2  
              02.SELECT * FROM table1 JOIN table2  
              03.SELECT * FROM table1,table2 
              SELECT * FROM table1 CROSS JOIN table2
              SELECT * FROM table1 JOIN table2
              SELECT * FROM table1,table2        由于其返回的结果为被连接的两个数据表的乘积,因此当有WHERE, ON或USING条件的时候一般不建议使用,因为当数据表项目太多的时候,会非常慢。一般使用LEFT [OUTER] JOIN或者RIGHT [OUTER] JOIN

               2.   内连接INNER JOIN 在MySQL中把INNER JOIN叫做等值连接,即需要指定等值连接条件在MySQL中CROSS和INNER JOIN被划分在一起。 join_table: table_reference [INNER | CROSS] JOIN table_factor [join_condition]

              3. MySQL中的外连接,分为左外连接和右连接,即除了返回符合连接条件的结果之外,还要返回左表(左连接)或者右表(右连接)中不符合连接条件的结果,相对应的使用NULL对应。

              例子:

              user表:

              id | name
              ———
              1 | libk
              2 | zyfon
              3 | daodao

              user_action表:

              user_id | action
              —————
              1 | jump
              1 | kick
              1 | jump
              2 | run
              4 | swim

              sql:


              01.select id, name, action from user as u 
              02.left join user_action a on u.id = a.user_id 
              select id, name, action from user as u
              left join user_action a on u.id = a.user_idresult:
              id | name    | action
              ——————————–
              1  | libk         | jump           ①
              1  | libk         | kick             ②
              1  | libk         | jump           ③
              2  | zyfon      | run               ④
              3  | daodao | null              ⑤

              分析:
              注意到user_action中还有一个user_id=4, action=swim的纪录,但是没有在结果中出现,
              而user表中的id=3, name=daodao的用户在user_action中没有相应的纪录,但是却出现在了结果集中
              因为现在是left join,所有的工作以left为准.
              结果1,2,3,4都是既在左表又在右表的纪录,5是只在左表,不在右表的纪录

               

              工作原理:

              从左表读出一条,选出所有与on匹配的右表纪录(n条)进行连接,形成n条纪录(包括重复的行,如:结果1和结果3),如果右边没有与on条件匹配的表,那连接的字段都是null.然后继续读下一条。

              引申:
              我们可以用右表没有on匹配则显示null的规律, 来找出所有在左表,不在右表的纪录, 注意用来判断的那列必须声明为not null的。
              如:
              sql:


              01.select id, name, action from user as u 
              02.left join user_action a on u.id = a.user_id 
              03.where a.user_id is NULL 
              select id, name, action from user as u
              left join user_action a on u.id = a.user_id
              where a.user_id is NULL
              (注意:

                      1.列值为null应该用is null 而不能用=NULL
                       2.这里a.user_id 列必须声明为 NOT NULL 的.


              上面sql的result:
              id | name | action
              ————————–
              3 | daodao | NULL

              ——————————————————————————–

              一般用法:

              a. LEFT [OUTER] JOIN:

              除了返回符合连接条件的结果之外,还需要显示左表中不符合连接条件的数据列,相对应使用NULL对应


              01.SELECT column_name FROM table1 LEFT [OUTER] JOIN table2 ON table1.column=table2.column 
               SELECT column_name FROM table1 LEFT [OUTER] JOIN table2 ON table1.column=table2.column
              b. RIGHT [OUTER] JOIN:

              RIGHT与LEFT JOIN相似不同的仅仅是除了显示符合连接条件的结果之外,还需要显示右表中不符合连接条件的数据列,相应使用NULL对应


              01.SELECT column_name FROM table1 RIGHT [OUTER] JOIN table2 ON table1.column=table2.column 
               SELECT column_name FROM table1 RIGHT [OUTER] JOIN table2 ON table1.column=table2.columnTips:

              1. on a.c1 = b.c1 等同于 using(c1)
              2. INNER JOIN 和 , (逗号) 在语义上是等同的
              3. 当 MySQL 在从一个表中检索信息时,你可以提示它选择了哪一个索引。
              如果 EXPLAIN 显示 MySQL 使用了可能的索引列表中错误的索引,这个特性将是很有用的。
              通过指定 USE INDEX (key_list),你可以告诉 MySQL 使用可能的索引中最合适的一个索引在表中查找记录行。
              可选的二选一句法 IGNORE INDEX (key_list) 可被用于告诉 MySQL 不使用特定的索引。如:


              01.mysql> SELECT * FROM table1 USE INDEX (key1,key2) 
              02.-> WHERE key1=1 AND key2=2 AND key3=3; 
              03.mysql> SELECT * FROM table1 IGNORE INDEX (key3) 
              04.-> WHERE key1=1 AND key2=2 AND key3=3; 
              mysql> SELECT * FROM table1 USE INDEX (key1,key2)
              -> WHERE key1=1 AND key2=2 AND key3=3;
              mysql> SELECT * FROM table1 IGNORE INDEX (key3)
              -> WHERE key1=1 AND key2=2 AND key3=3;

              2. 表连接的约束条件
               添加显示条件WHERE, ON, USING

              1. WHERE子句

              mysql>


              01.SELECT * FROM table1,table2 WHERE table1.id=table2.id; 
              SELECT * FROM table1,table2 WHERE table1.id=table2.id;
              2. ON

              mysql>


              01.SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id; 
              02. 
              03.SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id 
              04.LEFT JOIN table3 ON table2.id=table3.id; 
              SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;

              SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id
              LEFT JOIN table3 ON table2.id=table3.id;
              3. USING子句,如果连接的两个表连接条件的两个列具有相同的名字的话可以使用USING

               例如:

              SELECT FROM LEFT JOIN USING ()

               

              连接多于两个表的情况举例:

              mysql>


              01.SELECT artists.Artist, cds.title, genres.genre  
              02. 
              03.FROM cds  
              04. 
              05.LEFT JOIN genres N cds.genreID = genres.genreID  
              06. 
              07.LEFT JOIN artists ON cds.artistID = artists.artistID;  
              SELECT artists.Artist, cds.title, genres.genre

              FROM cds

              LEFT JOIN genres N cds.genreID = genres.genreID

              LEFT JOIN artists ON cds.artistID = artists.artistID;

               

              或者 mysql>


              01.SELECT artists.Artist, cds.title, genres.genre  
              02. 
              03.FROM cds  
              04. 
              05.LEFT JOIN genres ON cds.genreID = genres.genreID  
              06. 
              07. LEFT JOIN artists -> ON cds.artistID = artists.artistID 
              08. 
              09. WHERE (genres.genre = 'Pop');  
              SELECT artists.Artist, cds.title, genres.genre

              FROM cds

              LEFT JOIN genres ON cds.genreID = genres.genreID

               LEFT JOIN artists -> ON cds.artistID = artists.artistID

               WHERE (genres.genre = 'Pop');

              --------------------------------------------

               另外需要注意的地方 在MySQL中涉及到多表查询的时候,需要根据查询的情况,想好使用哪种连接方式效率更高。

               1. 交叉连接(笛卡尔积)或者内连接 [INNER | CROSS] JOIN

               2. 左外连接LEFT [OUTER] JOIN或者右外连接RIGHT [OUTER] JOIN 注意指定连接条件WHERE, ON,USING.

              3. MySQL如何优化LEFT JOIN和RIGHT JOIN
              在MySQL中,A LEFT JOIN B join_condition执行过程如下:

              1)·  根据表A和A依赖的所有表设置表B。

              2)·  根据LEFT JOIN条件中使用的所有表(除了B)设置表A。

              3)·   LEFT JOIN条件用于确定如何从表B搜索行。(换句话说,不使用WHERE子句中的任何条件)。

              4)·  可以对所有标准联接进行优化,只是只有从它所依赖的所有表读取的表例外。如果出现循环依赖关系,MySQL提示出现一个错误。

              5)· 进行所有标准WHERE优化。

              6)· 如果A中有一行匹配WHERE子句,但B中没有一行匹配ON条件,则生成另一个B行,其中所有列设置为NULL。

              7)· 如果使用LEFT JOIN找出在某些表中不存在的行,并且进行了下面的测试:WHERE部分的col_name IS NULL,其中col_name是一个声明为 NOT NULL的列,MySQL找到匹配LEFT JOIN条件的一个行后停止(为具体的关键字组合)搜索其它行。

              RIGHT JOIN的执行类似LEFT JOIN,只是表的角色反过来。

              联接优化器计算表应联接的顺序。LEFT JOIN和STRAIGHT_JOIN强制的表读顺序可以帮助联接优化器更快地工作,因为检查的表交换更少。请注意这说明如果执行下面类型的查询,MySQL进行全扫描b,因为LEFT JOIN强制它在d之前读?。?/p>


              01.SELECT * 
              02.FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) 
              03.WHERE b.key=d.key; 
              SELECT *
              FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key)
              WHERE b.key=d.key;
              在这种情况下修复时用a的相反顺序,b列于FROM子句中:


              01.SELECT * 
              02.FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) 
              03.WHERE b.key=d.key; 
              SELECT *
              FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key)
              WHERE b.key=d.key;
              MySQL可以进行下面的LEFT JOIN优化:如果对于产生的NULL行,WHERE条件总为假,LEFT JOIN变为普通联接。

              例如,在下面的查询中如果t2.column1为NULL,WHERE 子句将为false:


              01.SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5; 
              SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;因此,可以安全地将查询转换为普通联接:


              01.SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1; 
              SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;这样可以更快,因为如果可以使查询更佳,MySQL可以在表t1之前使用表t2。为了强制使用表顺序,使用STRAIGHT_JOIN。


              三、利用缓存来实现

              现在社区分享类网站很火,就拿方维购物分享网站举例说明吧。也是对二次开发方维购物分享网站的一点总结,高手可以飞过。

              购物分享的关键表有:分享表、图片表、文件表、评论表、标签表、分类表等。
              围绕分享的表就么多,哇,那也不少啊。当我们查看一个图片的详细信息时,就要显示以上表里的信息。显示图片所属的分类、给图片打的标签、图片的评论、有文件的话还要显示文件下载信息等。难道让我们6个表去关联查询嘛,当然不能这么多关联来查询数据,我们可以只查询一个表即可,这怎么讲?这里分享表是主表,我们可以在主表里建立一个缓存字段。比如我们叫cache_data字段,赋予它text类型,这样可以存储很长的字符串,而不至于超过字段的最大存储。

              这个缓存字段怎么用呢?在新增一条分享信息后,产生分享ID。如果用户发布图片或文件的话,图片信息入图片表,文件信息入文件表,然后把新产生的图片或文件信息写入到缓存字段里。同样的,如果用户有选择分类、打了标签的话,也把相应的信息写入到缓存字段里。对于评论而言,没有必要把全部评论存到缓存字段里,因为你不知道他有多少条记录,可以把最新的10条存到缓存字段里用于显示,这样缓存字段就变成一个二维或三维数组,序列化后存储到分享表里。

              array(
               
               'img' = array(
                name => '123.jpg',
                url  => 'http://tech.42xiu.com/123.jpg',
                width  => 800,
                width  => 600,
               ),

               'file' = array(
                name => 'abc.zip',
                download_url  => 'http://tech.42xiu.com/abc.zip',
                size  => 1.2Mb,
               ),

               'category' = array(
                1 => array(
                 id => 5,
                 name => PHP乐知博客
                ),

                2 => array(
                 id => 6,
                 name => PHP技术博客
                ),
               ),

               'tag' => array(
                tag1
                tag2
                ......
               ),

               'message' => array(
                1 => array(id, uid, name, content, time),
                2 => array(id, uid, name, content, time),
                3 => array(id, uid, name, content, time),
                4 => array(id, uid, name, content, time),
               ),

              )
              //比如,上面的数组结构,序列化存入数据库。

              UPDATE share SET cache_data=mysql_real_escape_string(serialize($cache_data)) WHERE id=1;这样查询就变得简单了,只需要查询一条就行了,取到缓存字段,把其反序列化,把数组信息提取出来,然后显示到页面。如果是以前那个结构,在几十万的数据量下,估计早崩溃了。数据缓存的方法也许不是最好的,如果你有更好的方法,可以相互学习,相互讨论。

              您可能感兴趣的文章:
              Mysql 多表联合查询效率分析及优化
              学习开启mysql慢查询与分析查询语句
              phpcms教程之mysql配置优化
              mysql中视图和union联合查询的使用
              MySQL 根据 status 状态优化
              有关php的缓存技术介绍
              mysql开启慢查询以检查查询慢的语句
              从哪些方面对ASP.NET进行性能优化
              mysql常用sql语句大全
              DB2数据库设计和最高性能原则

              [关闭]
              246好彩天天免费资枓大全 <二四六03024>| <二四六z资料>| <二四六老地主>| <二四六老地主论坛>| <246天天好彩玄机图>| <246天天好彩票玄机图片>| <246好彩天天免费资枓大全>| <二四六天天好彩彩玄机资枓>| <二四天天正版免费资枓大>| <二四六天天好彩每期文字賧料>| <二四六天天好彩毎期文字资料>| <二四六天天好彩毎期文字图片玄机>| <二四六天天人好彩网手机版>| <二四六天天好彩手机版—每期>| <二四六天天好彩免费网手机板>| <二四六天天好手机版本>| <二四六天天好彩彩玄机资枓>| <246好彩天天免费资枓大全>| <二四六天天好彩彩玄机资枓>| <二四天天正版免费资枓大>| <二四天天正版好彩免费资枓1>| <二四六天天好彩头首页>| <二四六天天网手机版>| <二四六玄机图片天天好彩玄机图>| <图片玄机二四六天天好彩资料大全 www.308k.com>| <二四六天天好彩费网站大全>| <精选二四六天天好彩手机版>| <二四六天天好资料大全168>| <二四六天天好来 资料大全>| <二四六天天好资料大全50期蓝月亮>| <246天天免费彩资料大全>| <二四六天天好彩资枓大全>| <二四天天正版免费资枓大全>| <二四六天天好彩免费全年资枓大全>| <二四六天天免费好彩资料大全>| <二四六天天免费好彩资料图>| <二四六天天免费好彩资料大全168>| <743cc二四六天天好釆免费资料>| <246好彩天天免费资枓大全>| <天下釆彩与你同行资料二四六>| <二四六天天好彩资料246>| <二四六天天玄机资料大全>| <308二四六玄机资料大全二四六天天玄机图资料>| <香港二四六玄机资料>| <3o8k com二四六天天好彩文字资枓>| <246好彩天天免费资枓大全>| <二四六好彩资料大全308kk>| <二四六天天好彩彩免费资料大全>| <743cc二四六天天好釆免费资料>| <734cc期期好彩免费资枓大全>| <二四六好彩正版资料>| <308k二四六天好彩资料大全>| <二四六天天,好彩资料开奖>| <玄机二四六天天彩>| <二四六天天天好彩图片玄机>| <二四六天天好彩玄机图库>| <二四六天天如彩正版免费资料大全>| <二四六天天彩玄机免费资料大全>| <二四六天天好彩每期文资子料大全>| <二四六天天香港好彩资料大全>| <二四六天天好彩资料免费大全送>| <香港二四六天天好彩正版资料大全>| <308k二四六好彩资料大全>| <246天天彩免费资料308k>| <246天天好彩资料app>| <二四六天天好彩app下载>| <500502二四六天天彩>| <天天好彩246app>| <246天天好彩资料app>| <二四六天天好彩一每期文字资料>| <二四六天天好彩图片玄机下载>| <246好彩天天免费资枓大全>| <天下釆彩与你同行资料二四六>| <246免费资料大全天天好彩>| <246免费资料大全开>| <246好彩天天免费资枓大全>| <246天天好·彩免费资料大全>| <246天天好彩正版资>| <246天天好彩免费大全资料308k>| | | <新址246天天好彩>| <新址天天好彩二四六>| <246天天好彩开奖944cc>| <246好彩天天免费资枓大全>| <图玄机246天天好彩资料>| <246天天好彩资料全>| <246天天好彩玄机图片>| <246天天好彩免费944cc>| <246556 民间高手论坛>| <246正版天天好彩免费资枓大全>| <246正板天天好彩免费资枓大全>| <308kcom二四六天天彩>| <246玄机图资料天天好彩>| <246天天好彩免费资料大全308>| <二四六免费资料大全正>| <二四六天空彩资料大全>| <二四六天天好彩兔费咨料大全>| <246zl天天好·彩免费资料大全>| <246zl天天944cc好彩免费资料大全>| <二四六正版免费资料大全743cc>| <二四六天天好彩资料大全首页>| <二四六天天好彩免费资料308k>| <二四六免费资料玄机>| <二四六天天好彩资免费大全资料>| <308k二四六天天好彩i>| <246zl天天好·彩免费资料大全>| <二四六天天好彩网手机版 免费>| <天天好彩246资料308图库>| <246天天免费资料大全开奖结果>| <246天天免费资料大全玄机>| <二四六天天好彩免费资料大全168i>| <二四六天天好彩zl246cc>| <精选好彩二四六天天好彩>| <黄大仙精选二四六天天好彩>| | <蓝月亮精选二四六免费天天好彩>| <二四六天天好彩全年免费玄机料>| <二四六图片玄机资料大全>| <二四六玄机图片花仙子>| <香港二四六玄机资料图>| <二四六天天好采玄机资料大全>| <天天二四六玄机>| <二四六天天好彩免费资枓全免费>| <二四六天天好彩资枓免费>| <玄机图二四六天天好彩免费资料>| <二四六天天彩与你同行开奖>| <246好彩天天免费资枓大全>| <二四六天天手机版玄机图资料大全>| <308kcom二四六天天好彩玄机资料>| <二四六好彩正版资料大全>| <香港二四六天天好彩兔费资>| <308k二四六天天好彩 资料>| <二四六玄机图 彩图102>| <二四六天天彩正版资料>| <香港二四六玄机图>| <香港二四六好彩资料246>| <308kcom二四六玄机资料>| <二四六天天好彩正版文字资料大全>| <246天天好彩免费开奖结果>| <246天天好彩免费开奖资料>| <246天天好彩免费资料正版资料>| <2246天天好彩图片玄机>| <246天天好彩图片机>| <二四六天天网彩手机版>| <246 天天好彩免费资料成语挂牌>| <246天天好彩管家婆资料大全>| <246天天好彩综合资料大全>| <308k二四六天天彩>| <二四六天天彩免费玄机资料>| <新址246天天好彩282cc>| <246天天好彩免费944cc>| | <二四六天天好彩944cc资讯>| <246天天好彩308k每期资料>| <246天天好彩308每期资料>| <二四六好彩免费资料图片玄机>| <新址246正版免费资料大全>| <246天天好彩勉费资料大全246>| <新址246zlcom天天好彩资料>| <新址zl 246天天好彩>| <新址246zl cc天天好彩>| <246天天好彩118图片玄机>| <二四六天天好彩马会开奖结果>| <二四六天天好彩手机版开奖结果>| <二四六天天好彩综合资料大全>| <二四六天天好彩308k con>| <二四六天天好彩308k kom>| <246天天好彩免费资大全>| <新址zl246net天天好彩大全>| <246天天好彩玄机资料手机版>| <246天天好天下天空免费>| <二四六天空釆资料大全>| <二四六兔费天天好彩资料>| <二四六308kcom文字资料>| <246天天好天下彩天空开奖>| <二四六免费资料天下>| <二四六天天好彩308k玄机图>| <二四六天天好彩资料开奖>| <308k二四六天天好彩每期>| <308k二四六天天好彩图片玄机>| <二四六天天好彩246zl免费>| <二四六天天好彩 944cc 彩图>| <蓝月亮精选二四六天天好彩>| <二四六天天好彩资料网手机板>| <二四六天天好彩玄机图手机版>| <二四六论坛图片玄机>| <天天二四六玄机图>| <天天彩246免费资料大全>| <246天天好好彩资料免费大全>| <246天天好好彩资料大全>| <二四六免费大全天天彩308>| <香港二四六论坛308k>| <二四六天天彩正版资料大全>| <二四六论坛玄机资料大全>| <308kcom二四六玄机图片>| <308kcom二四六图片玄机>| <308kcom二四六生活幽默>| <玄机图片二四六好彩网>| <玄机资料二四六好彩资料大全>| <246天天好彩308k每期资料大全>|