问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

问个mysql优化问题

发布网友 发布时间:2022-04-22 16:35

我来回答

4个回答

热心网友 时间:2022-04-07 16:20

在开始演示之前,我们先介绍下两个概念。


概念一,数据的可选择性基数,也就是常说的cardinality值。


查询优化器在生成各种执行计划之前,得先从统计信息中取得相关数据,这样才能估算每步操作所涉及到的记录数,而这个相关数据就是cardinality。简单来说,就是每个值在每个字段中的唯一值分布状态。


比如表t1有100行记录,其中一列为f1。f1中唯一值的个数可以是100个,也可以是1个,当然也可以是1到100之间的任何一个数字。这里唯一值越的多少,就是这个列的可选择基数。


那看到这里我们就明白了,为什么要在基数高的字段上建立索引,而基数低的的字段建立索引反而没有全表扫描来的快。当然这个只是一方面,至于更深入的探讨就不在我这篇探讨的范围了。


概念二,关于HINT的使用。


这里我来说下HINT是什么,在什么时候用。


HINT简单来说就是在某些特定的场景下人工协助MySQL优化器的工作,使她生成最优的执行计划。一般来说,优化器的执行计划都是最优化的,不过在某些特定场景下,执行计划可能不是最优化。


比如:表t1经过大量的频繁更新操作,(UPDATE,DELETE,INSERT),cardinality已经很不准确了,这时候刚好执行了一条SQL,那么有可能这条SQL的执行计划就不是最优的。为什么说有可能呢?


来看下具体演示


譬如,以下两条SQL,

热心网友 时间:2022-04-07 17:38

在一张有几百万个大数据的表中,MySQL的处理引擎会查找得很慢,这时,就必须采用分表甚至分库的方法。


你可以参考这篇文章:《MySQL大数据处理》

http://www.cnblogs.com/buffer/archive/2011/04/16/2018531.html

摘录如下:

一、概述


分表是个目前算是比较炒的比较流行的概念,特别是在大负载的情况下,分表是一个良好分散数据库压力的好方法。


首先要了解为什么要分表,分表的好处是什么。我们先来大概了解以下一个数据库执行SQL的过程:


接收到SQL --> 放入SQL执行队列 --> 使用分析器分解SQL --> 按照分析结果进行数据的提取或者修改 --> 返回处理结果


当然,这个流程图不一定正确,这只是我自己主观意识上这么我认为。那么这个处理过程当中,最容易出现问题的是什么?就是说,如果前一个SQL没
有执行完毕的话,后面的SQL是不会执行的,因为为了保证数据的完整性,必须对数据表文件进行锁定,包括共享锁和独享锁两种锁定。共享锁是在锁定的期间,
其它线程也可以访问这个数据文件,但是不允许修改操作,相应的,独享锁就是整个文件就是归一个线程所有,其它线程无法访问这个数据文件。一般MySQL中
最快的存储引擎MyISAM,它是基于表锁定的,就是说如果一锁定的话,那么整个数据文件外部都无法访问,必须等前一个操作完成后,才能接收下一个操作,
那么在这个前一个操作没有执行完成,后一个操作等待在队列里无法执行的情况叫做阻塞,一般我们通俗意义上叫做“锁表”。


锁表直接导致的后果是什么?就是大量的SQL无法立即执行,必须等队列前面的SQL全部执行完毕才能继续执行。这个无法执行的SQL就会导致没有结果,或者延迟严重,影响用户体验。


特别是对于一些使用比较频繁的表,比如SNS系统中的用户信息表、论坛系统中的帖子表等等,都是访问量大很大的表,为了保证数据的快速提取返回给用户,必须使用一些处理方式来解决这个问题,这个就是我今天要聊到的分表技术。


分表技术顾名思义,就是把若干个存储相同类型数据的表分成几个表分表存储,在提取数据的时候,不同的用户访问不同的表,互不冲突,减少锁表的几
率。比如,目前保存用户分表有两个表,一个是user_1表,还有一个是 user_2 表,两个表保存了不同的用户信息,user_1
保存了前10万的用户信息,user_2保存了后10万名用户的信息,现在如果同时查询用户 heiyeluren1 和 heiyeluren2
这个两个用户,那么就是分表从不同的表提取出来,减少锁表的可能。


我下面要讲述的两种分表方法我自己都没有实验过,不保证准确能用,只是提供一个设计思路。下面关于分表的例子我假设是在一个贴吧系统的基础上来进行处理和构建的。(如果没有用过贴吧的用户赶紧Google一下)


二、基于基础表的分表处理


这个基于基础表的分表处理方式大致的思想就是:一个主要表,保存了所有的基本信息,如果某个项目需要找到它所存储的表,那么必须从这个基础表中
查找出对应的表名等项目,好直接访问这个表。如果觉得这个基础表速度不够快,可以完全把整个基础表保存在缓存或者内存中,方便有效的查询。


我们基于贴吧的情况,构建假设如下的3张表:


1. 贴吧版块表: 保存贴吧中版块的信息


2. 贴吧主题表:保存贴吧中版块中的主题信息,用于浏览


3. 贴吧回复表:保存主题的原始内容和回复内容


“贴吧版块表”包含如下字段:


版块ID       board_id          int(10)


版块名称    board_name      char(50)


子表ID       table_id            smallint(5)


产生时间    created             datetime


“贴吧主题表”包含如下字段:


主题ID          topic_id        int(10)


主题名称        topic_name     char(255)


版块ID          board_id          int(10)


创建时间       created           datetime


“贴吧回复表”的字段如下:


回复ID        reply_id           int(10)


回复内容      reply_text        text


主题ID        topic_id           int(10)


版块ID        board_id         int(10)


创建时间      created            datetime


那么上面保存了我们整个贴吧中的表结构信息,三个表对应的关系是:


版块 --> 多个主题


主题 --> 多个回复


那么就是说,表文件大小的关系是:


版块表文件 < 主题表文件 < 回复表文件


所以基本可以确定需要对主题表和回复表进行分表,已增加我们数据检索查询更改时候的速度和性能。


看了上面的表结构,会明显发现,在“版块表”中保存了一个"table_id"字段,这个字段就是用于保存一个版块对应的主题和回复都是分表保存在什么表里的。


比如我们有一个叫做“PHP”的贴吧,board_id是1,子表ID也是1,那么这条记录就是:


board_id | board_name | table_id | created


1 | PHP | 1 | 2007-01-19 00:30:12


相应的,如果我需要提取“PHP”吧里的所有主题,那么就必须按照表里保存的table_id来组合一个存储了主题的表名称,比如我们主题表的前缀是“topic_”,那么组合出来“PHP”吧对应的主题表应该是:“topic_1”,那么我们执行:


SELECT * FROM topic_1 WHERE board_id = 1 ORDER BY topic_id DESC LIMIT 10


这样就能够获取这个主题下面回复列表,方便我们进行查看,如果需要查看某个主题下面的回复,我们可以继续使用版块表中保存的“table_id”来进行查询。比如我们回复表的前缀是“reply_”,那么就可以组合出“PHP”吧的ID为1的主题的回复:


SELECT * FROM reply_1 WHERE topic_id = 1 ORDER BY reply_id DESC LIMIT 10


这里,我们能够清晰的看到,其实我们这里使用了基础表,基础表就是我们的版块表。那么相应的,肯定会说:基础表的数据量大了以后如何保证它的速度和效率?


当然,我们就必须使得这个基础表保持最好的速度和性能,比如,可以采用MySQL的内存表来存储,或者保存在内存当中,比如Memcache之类的内存缓存等等,可以按照实际情况来进行调整。


一般基于基础表的分表机制在SNS、交友、论坛等Web2.0网站中是个比较不错的解决方案,在这些网站中,完全可以单独使用一个表来来保存基本标识和目标表之间的关系。使用表保存对应关系的好处是以后扩展非常方便,只需要增加一个表记录。


【优势】增加删除节点非常方便,为后期升级维护带来很大便利


【劣势】需要增加表或者对某一个表进行操作,还是无法离开数据库,会产生瓶颈


三、基于Hash算法的分表处理


我们知道Hash表就是通过某个特殊的Hash算法计算出的一个值,这个值必须是惟一的,并且能够使用这个计算出来的值查找到需要的值,这个叫做哈希表。


我们在分表里的hash算法跟这个思想类似:通过一个原始目标的ID或者名称通过一定的hash算法计算出数据存储表的表名,然后访问相应的表。


继续拿上面的贴吧来说,每个贴吧有版块名称和版块ID,那么这两项值是固定的,并且是惟一的,那么我们就可以考虑通过对这两项值中的一项进行一些运算得出一个目标表的名称。


现在假如我们针对我们这个贴吧系统,假设系统最大允许1亿条数据,考虑每个表保存100万条记录,那么整个系统就不超过100个表就能够容纳。按照这个标准,我们假设在贴吧的版块ID上进行hash,获得一个key值,这个值就是我们的表名,然后访问相应的表。


我们构造一个简单的hash算法:


function get_hash($id){
     $str = bin2hex($id);
     $hash = substr($str, 0, 4);
     if (strlen($hash)<4){
         $hash = str_pad($hash, 4, "0");
     }
     return $hash;
}


算法大致就是传入一个版块ID值,然后函数返回一个4位的字符串,如果字符串长度不够,使用0进行补全。


比如:get_hash(1),输出的结果是“3100”,输入:get_hash(23819),得到的结果是:3233,那么我们经过简单的跟表前缀组合,就能够访问这个表了。那么我们需要访问ID为1的内容时候哦,组合的表将是:topic_3100、reply_3100,那么就可以直接对目标表进行访问了。


当然,使用hash算法后,有部分数据是可能在同一个表的,这一点跟hash表不同,hash表是尽量解决冲突,我们这里不需要,当然同样需要预测和分析表数据可能保存的表名。


如果需要存储的数据更多,同样的,可以对版块的名字进行hash操作,比如也是上面的二进制转换成十六进制,因为汉字比数字和字母要多很多,那么重复几率更小,但是可能组合成的表就更多了,相应就必须考虑一些其它的问题。


归根结底,使用hash方式的话必须选择一个好的hash算法,才能生成更多的表,然数据查询的更迅速。


【优点hash算法直接得出目标表名称,效率很高】通过


【劣势】扩展性比较差,选择了一个hash算法,定义了多少数据量,以后只能在这个数据量上跑,不能超过过这个数据量,可扩展性稍差


四、其它问题


1. 搜索问题


现在我们已经进行分表了,那么就无法直接对表进行搜索,因为你无法对可能系统中已经存在的几十或者几百个表进行检索,所以搜索必须借助第三方的组件来进行,比如Lucene作为站内搜索引擎是个不错的选择。


2. 表文件问题


我们知道MySQL的MyISAM引擎每个表都会生成三个文件,*.frm、*.MYD、*.MYI
三个文件,分表用来保存表结构、表数据和表索引。Linux下面每个目录下的文件数量最好不要超过1000个,不然检索数据将更慢,那么每个表都会生成三
个文件,相应的如果分表超过300个表,那么将检索非常慢,所以这时候就必须再进行分,比如在进行数据库的分离。


使用基础表,我们可以新增加一个字段,用来保存这个表保存在什么数据。使用Hash的方式,我们必须截取hash值中第几位来作为数据库的名字。这样,完好的解决这个问题。


五、总结


在大负载应用当中,数据库一直是个很重要的瓶颈,必须要突破,本文讲解了两种分表的方式,希望对很多人能够有启发的作用。当然,本文代码和设想没有经过任何代码测试,所以无法保证设计的完全准确实用,具体还是需要读者在使用过程当中认真分析实施。

热心网友 时间:2022-04-07 19:13

  数据库优化的问题需要从多个角度考虑:

  一、针对数据库结构和查询的优化:
  在一般的应用中,合理的数据表结构和索引的设计,能够最大化查询性能。即时在千万级别的数据表中,针对主键的查询也会非常快速。在数据量太大的情况下,没有使用索引的查询可能会非常缓慢。where条件会用到的字段中,要尽量都加上索引。模糊查询可以通过全文索引来优化。另外,单条记录的长短也会对查询速率产生一定的影响(记录越长,磁盘读取数据时需要移动的距离就越长)。一些关键的数据最好放在小表中。存储引擎的选择也很重要。MYISAM引擎的查询性能最好,而且支持全文索引。MYISAM的索引是压缩存储的,可以节约磁盘空间。更重要的时,它可以将更多的索引加载到内存中,大大提高查询效率。

  二、针对架构的优化:
  在高并发的应用中,仅仅针对数据库层面的优化已经力不从心。数据库的能力是有限的,最优秀的数据库也存在性能瓶颈。大量的并发查询将导致数据库不堪重负。主从库、读写分离是常见的优化方式。对于一些经常访问的热数据,每次都执行数据库查询会造成资源浪费,而且非常低效。如果将这些热的数据以key-value(键和值)的方式存储在内存中,可以最大化性能。

  一些热门的应用,如你提到的微博,除了做好数据库方面的优化外,架构优化非常关键。本例中,可以为每个用户单独存储好友的最新微博。在用户发布微博时,将这条微博的ID存储在所有好友的“最新微博”中。数据满30条时,同时删除旧的数据。这样在获取好友最新微博时,不需要查询数据库,效率非常高。

热心网友 时间:2022-04-07 21:04

大型项目,一般采用子表,即当用户注册后,为此用户建立单独的数据表。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
招聘和招募和招收区别 人力资源中招聘与招募的区别 招聘与招募有啥区别 夏日繁星公众号可信吗 关于“红杏出墙”的古诗词描写有哪些 需要考多少分才过雅思 雅思考试多少分才可以算及格 雅思考试多少分算及格 雅思的总分多少分及格 雅思一般考多少分能合格 mysql 中时间段查询如何优化 mysql数据量大通过时间范围查询如何优化 枸杞有什么用处 枸杞有什么作用 枸杞的用途 枸杞的主要作用是什么 高铁动车顶上的两根线分别是干什么用的? 高铁票上面的信息各是什么意思? 高铁上面的“CRH”是什么意思? 高铁票上的信息各代表什么? 高铁车票上的G D C是什么意思? iphone更新不能使用蜂窝 iphone蜂窝网络需要更新才能使用? 高铁上的饮料都是免费的吗 苹果12为什么蜂窝数据里面没有用量? 高铁上的二等座是什么情况? iphone在更新之前无法拨打和接听电话或访问蜂窝数据 高铁上的事情 苹果蜂窝数据清零不了 高铁上的常识 MySQL服务器如何进行调优?? mysql优化一般需要做哪些?其他数据库优化也行(sql) mysql 千万级数据 分页优化 条件是某个日期 mysql如何限定时间范围 郑州高铁站附近医院叫什么 宁波哪家医院可做核酸检测在高铁站北广场附近? 虹口区医院有哪些医院距虹桥高铁站最近? 离长沙南站(高铁站)最近的三甲医院 离青川县高铁站最近的医院是哪个医院? 靠近杭州高铁站附近有哪家三甲医院? 坐高铁去上海华山医院看病,上海哪个高铁站离这医... 北京哪个高铁站离儿童医院近? 离沈阳高铁站近的三甲级医院? 上海哪个高铁站离杨浦区长海医院近 北京协和东西两院那个医院离高铁站较近 上海哪个高铁站离杨浦区长海医院近? 长沙南站附近的医院 唐山高铁站离哪个做核酸检测的医院最近? 上海仁济医院东院离哪个高铁站近? 上海哪些三甲医院离高铁站近