mysql大数据量处理  



以下是个人的总结,有不对的地方大家指点:

设计上:
冗余:有些能冗余的就冗余吧,尽量少关联表;
垂直分区,一条记录中有text,varchar()这些能拆出来就拆出来,能用小的类型就用小的类型,如:char替换varchar之类的,能使用smallint,int就不要使用long等更大的数字型;
水平分区:range,list,hash,key,composite分区,这里分区说一下range是less than 的,查分区时会查前后的分区,list的in是range的相象,不过只查一个分区,composite是一个组合分区了,对于更超大的合适,先用range/list然后再hash/key分区;


目前mysql分区只支持内置的日志函数有:year,month,to_day

物理上:
分区与索引存放在不同的物理分区上;
隔一定时间使数据迁移走做备份

查询语句:
查询中不要使用*做查询返回字段,应写字段;尽量不要使用嵌套语句;
尽量使用更好的关系语句;
尽量少关联表;
查询大数据表的时候尽量不要返回text,varchar类型字段,并且这些字段最好就不要放在同一张表中,同过ID再查详情之类形式返回

操作上:
尽量让操作与查询分离,特别是在大并发操作的时候;

配置上:
对mysql的配置参数优化,
如key_buffer这些缓存可以设大点的:默认是8M吧,设到400M也不过份的(索引缓存);
sort_buffer_size默认是5M,可以放到32M






从3张表中取数据,求一个更好的sql语句 

表1: 
 CREATE TABLE `CorporationServer` ( 
   `corporationServerID` int(11) NOT NULL AUTO_INCREMENT, 
   `corporationKey` int(11) NOT NULL, 
   `shelfCode` varchar(24) DEFAULT NULL, 
   `floorCode` varchar(24) DEFAULT NULL, 
   `ip` int(10) unsigned NOT NULL, 
   `isWhite` tinyint(1) DEFAULT '0', 
   PRIMARY KEY (`corporationServerID`), 
   UNIQUE KEY `AK_Key_2` (`ip`), 
   KEY `R_31` (`corporationKey`) 
 ) ENGINE=MyISAM AUTO_INCREMENT=65537 DEFAULT CHARSET=utf8; 

 表2: 
 CREATE TABLE `IpCapture` ( 
   `ipCaptureID` int(11) NOT NULL AUTO_INCREMENT, 
   `ip` int(10) unsigned NOT NULL, 
   `serviceType` varchar(128) DEFAULT NULL, 
   `proxyType` smallint(6) DEFAULT NULL , 
   `sectScope` tinyint(1) DEFAULT '0', 
   PRIMARY KEY (`ipCaptureID`), 
   UNIQUE KEY `AK_Key_2` (`ip`) 
 ) ENGINE=MyISAM AUTO_INCREMENT=65618 DEFAULT CHARSET=utf8 ; 

 表(分区)3:#这里是一天个分区,每天的数据最小量限为300W算 

 create table HttpGetLogPart2 
 ( 
   httpGetLogID        bigint(12) not null  auto_increment, 
   dstIp                int unsigned  not null, 
   dstPort              NUMERIC(5) not null, 
   srcIp                int unsigned  not null, 
   srcPort              SMALLINT not null, 
   domainName          VARCHAR(64) not null, 
   visitTime            TIMESTAMP not null default CURRENT_TIMESTAMP, 
   urlHashcode          bigint, 
   getUrl              text, 
   vlanID              INTEGER default -1, 
   probeIp              VARCHAR(16) not null, 
   inputDate            date  default null, 
   primary key (httpGetLogID, inputDate) 
 )  engine=myisam  
         PARTITION BY list (to_days(inputDate)) ( 
         PARTITION p0 VALUES in (to_days('2008-07-05')), 
     PARTITION p1 VALUES in (to_days('2008-07-06')), 
         PARTITION p2 VALUES in (to_days('2008-07-07')), 
         PARTITION p3 VALUES in (to_days('2008-07-08')), 
         PARTITION p4 VALUES in (to_days('2008-07-09')));        

 create index Index_dstip on HttpGetLogPart2 
 ( 
   dstIp 
 );        


 表HttpGetLogPart2:        16711680条记录; 
 表IpCapture:65617条记录; 
 表CorporationServer:65536条记录 

 查询语句: 
 select * from HttpGetLogPart2  log,IpCapture ipcapture ,CorporationServer 
 corporationServer 
 where( 
 log.inputDate> date '2008-07-06' and log.inputDate <date '2008-07-09' 
 and ipcapture.ip = log.dstIp 
 and corporationServer.ip = log.dstIp 
 ) order by httpGetLogID desc limit 600000,15; 

 结果:15 rows in set (25.20 sec) 

 查询总和: 
 select count(*) from HttpGetLogPart2  log,IpCapture ipcapture ,CorporationServer 
 corporationServer 
 where( 
 log.inputDate> date '2008-07-06' and log.inputDate <date '2008-07-09' 
 and  log.dstIp =  ipcapture.ip 
 and  log.dstIp = corporationServer.ip 
 ); 
 +----------+ 
 ? count(*) ? 
 +----------+ 
 ?  6684672 ? 
 +----------+ 
 1 row in set (25.58 sec)




查询的结果不怎么理想,计算下总和与查下数据,合起来的时间差不多一分钟了; 

大家帮忙设计个sql语句吧,谢谢 

以下是我慢慢实践的总结:

在这里修改了下,把查询语句中的*改成字段了,还度提升到17秒左右,再去掉order by速度为2.26秒左右
这里可以看到查询语句中的字段最好能确认那些需要查询的;

但这里的order by 很影响性能呀,大家指下啦,谢谢


还在查询总和的时候还是得不到更好的解决

暂时是通过sort_buffer_size默认是5M,可以放到32M来优化下,
另外一个思路就是先最小字段倒序查询出主键,现通过in来取到最后的结果,但这些都需要explain与实际查询的;

mysql 的myisam表会记录着表中所存在的总数count(),所以select count(*) 是很快的,但加上了where那速度就直线下降了