1. 程式人生 > >SQL優化,百萬級2張表關聯,從40分鐘到3秒的歷程

SQL優化,百萬級2張表關聯,從40分鐘到3秒的歷程

  1. <strong>表結構如下:</strong>  
  1. CREATETABLE `deviceback` (  
  2.   `id` int(11) NOTNULL AUTO_INCREMENT,  
  3.   `imei` varchar(100) NOTNULL COMMENT '手機唯一標識',  
  4.   `mid` varchar(50) DEFAULTNULL,  
  5.   `mac` varchar(100) DEFAULTNULL,  
  6.   `APNType` varchar(100) DEFAULTNULL,  
  7.   `status` int(11) DEFAULT'0',  
  8.   `ip` varchar
    (100) DEFAULTNULL,  
  9.   `sn` varchar(100) DEFAULTNULL COMMENT '系列號',  
  10.   `oem` varchar(100) DEFAULTNULL COMMENT '廠商',  
  11.   `product` varchar(100) DEFAULTNULL COMMENT '產品',  
  12.   `region` varchar(100) DEFAULTNULL COMMENT '區域',  
  13.   `operator` varchar(100) DEFAULTNULL COMMENT '運營商',  
  14.   `sim` varchar(100) DEFAULTNULL COMMENT 
    'sim卡號',  
  15.   `push_time` timestampNULLDEFAULTNULL COMMENT '第一次登陸時間',  
  16.   `origin_version` varchar(100) DEFAULTNULL COMMENT '原始版本',  
  17.   `province` varchar(100) DEFAULTNULL COMMENT '省份',  
  18.   `provinceCode` varchar(100) DEFAULTNULL COMMENT '省份code',  
  19.   `city` varchar(50) DEFAULTNULL COMMENT '城市',  
  20.   `cityCode` varchar
    (50) DEFAULTNULL COMMENT '城市code',  
  21.   `brands` varchar(50) DEFAULT'0',  
  22.   `version` varchar(100) DEFAULT'0' COMMENT '客戶端版本號',  
  23.   `last_checktime` timestampNULLDEFAULTNULL COMMENT '最後一次登入時間',  
  24.   PRIMARYKEY (`id`),  
  25.   FULLTEXT KEY `NewIndex1` (`imei`),  
  26.   FULLTEXT KEY `NewIndex2` (`mid`),  
  27.   FULLTEXT KEY `NewIndex3` (`product`),  
  28.   FULLTEXT KEY `NewIndex4` (`brands`)  
  29. ) ENGINE=MyISAM AUTO_INCREMENT=6832460 DEFAULT CHARSET=utf8;  
  1. CREATETABLE `20130602_AppLog` (  
  2.   `id` int(11) NOTNULL AUTO_INCREMENT,  
  3.   `imei` varchar(100) DEFAULTNULL,  
  4.   `mid` varchar(50) NOTNULLDEFAULT'',  
  5.   `status` char(1) NOTNULLDEFAULT'0',  
  6.   `mac` varchar(100) DEFAULT'NULL',  
  7.   `sn` varchar(100) DEFAULTNULL,  
  8.   `sim` varchar(100) DEFAULTNULL,  
  9.   `coperator` varchar(100) DEFAULTNULL,  
  10.   `version` varchar(100) DEFAULTNULL,  
  11.   `logintime` datetime DEFAULTNULL,  
  12.   `ip` varchar(20) DEFAULTNULL,  
  13.   `origin_version` varchar(100) DEFAULTNULL,  
  14.   `now_version` varchar(100) DEFAULTNULL,  
  15.   `APNType` varchar(20) DEFAULTNULL,  
  16.   `oem` varchar(20) DEFAULTNULL,  
  17.   `product` varchar(100) DEFAULTNULL,  
  18.   `region` varchar(100) DEFAULTNULL,  
  19.   `operator` varchar(100) DEFAULTNULL,  
  20.   PRIMARYKEY (`id`),  
  21.   FULLTEXT KEY `NewIndex1` (`imei`),  
  22.   FULLTEXT KEY `NewIndex2` (`mid`)  
  23. ) ENGINE=MyISAM AUTO_INCREMENT=3123866 DEFAULT CHARSET=utf8;  


SQL如下:

  1. <strong>SELECT *  
  2. FROM   deviceback d,20130602_AppLog g  
  3. WHERE d.mid=g.mid  
  4.       AND d.imei=g.imei  
  5.       AND d.mac=g.mac  
  6.       AND d.brands=0  
  7.       AND g.coperator <> '' limit 20;</strong>  


explain

結果:

從這裡可以看到ALL以及key為NULL,就是全表掃描,沒有走索引,索引失效了!

1 然後我建議建上加上聯合索引,試試看效果如何:

2 效果還是比較慢的,看來得換種辦法了,檢查所有關聯欄位,將為null的資料改成''。還是沒有效果。

3  不查*了,直接count(*)  看看結果集大小,結果還是卡住了,短時間內沒有出查詢結果。

4,到這裡我猜測估計是資料的構成問題,那就一個個條件去掉去嘗試了。

SELECT *
FROM   deviceback d,20130602_AppLog g
WHERE d.mid=g.mid
      AND d.imei=g.imei
      AND d.mac=g.mac
      AND d.brands=0 limit 20;
去掉<> 條件試試看,God,結果是37秒就出來了,好,大概問題找到了,出在<>這條判斷語句裡面,也就是
AND g.coperator <> '' 這個影響還蠻大的。 那就先在20130602_AppLog 表的coperator欄位單獨建索引試試看,然後查下 20130602_AppLog裡面 g.coperator <> ''的有多少?
結果是比較令人欣慰的,單獨查詢,一秒不到出來結果了,6W多條紀錄。  SELECT COUNT(1) 
       FROM 20130602_AppLog gg
       WHERE gg.coperator <> ''
63987
  然後再試試整個sql,看需要多長時間。 先看下explain結果:     SELECT *
FROM   deviceback d,20130602_AppLog g
WHERE d.mid=g.mid
      AND d.imei=g.imei
      AND d.mac=g.mac
      AND d.brands=0
      AND g.coperator <> '' limit 20; Great,不到3秒就出來結果了。 5,limit 20是OK了,我還想試試不限制limit的話,要多久可以查詢出來結果。 直接執行 SELECT *
FROM   deviceback d,20130602_AppLog g
WHERE d.mid=g.mid
      AND d.imei=g.imei
      AND d.mac=g.mac
      AND d.brands=0
      AND g.coperator <> '' ; 卡住了,很久都沒有出來結果,在想是否是資料的問題?切換下where條件後面的欄位順序試試看。   SELECT d.mid,g.mac,
FROM   deviceback d,20130602_AppLog g
WHERE 
       d.imei=g.imei
      AND d.mac=g.mac
      AND d.mid=g.mid
      AND d.brands=0
      AND g.coperator <> '' ;

 OK,27秒出來了,AND d.mid=g.mid這個之前在第一條,現在放在後面,原因是手機唯一標示這個欄位有空值。

God,最討厭關鍵業務欄位null值了,給我們的優化工作帶來巨大的煩惱。

切記:大家以後千萬要記住關鍵業務欄位不能允許錄入null值。