2011-11-01 46 views
0

我想我已经优化了我所能做以下表结构:没有更多的MySQL表优化?

CREATE TABLE `sal_forwarding` (
    `sid` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `f_shop` INT(11) NOT NULL, 
    `f_offer` INT(11) DEFAULT NULL, 
    . 
    . 
    . 
    . 
    . 
    `f_affiliateId` TINYINT(3) UNSIGNED NOT NULL, 
    `forwardDate` DATE NOT NULL, 
    PRIMARY KEY (`sid`), 
    KEY `f_partner` (`f_partner`,`forwardDate`), 
    KEY `forwardDate` (`forwardDate`,`cid`), 
    KEY `forwardDate_2` (`forwardDate`,`f_shop`), 
    KEY `forwardDate_3` (`forwardDate`,`f_shop`,`f_partner`), 
    KEY `forwardDate_4` (`forwardDate`,`f_partner`,`cid`), 
    KEY `forwardDate_5` (`forwardDate`,`f_affiliateId`), 
    KEY `forwardDate_6` (`forwardDate`,`f_shop`,`sid`), 
    KEY `forwardDate_7` (`forwardDate`,`f_shop`,`cid`), 
    KEY `forwardDate_8` (`forwardDate`,`f_affiliateId`,`cid`) 
) ENGINE=INNODB AUTO_INCREMENT=10946560 DEFAULT CHARSET=latin1 

这是EXPLAIN语句:

id select_type table   type possible_keys                         key    key_len ref  rows Extra 
1 SIMPLE  sal_forwarding range forwardDate,forwardDate_2,forwardDate_3,forwardDate_4,forwardDate_5,forwardDate_6,forwardDate_7,forwardDate_8 forwardDate_7 3  (NULL) 1221784 Using where; Using index; Using filesort 

下面的查询需要23秒阅读2300行:

SELECT COUNT(sid),f_shop, COUNT(DISTINCT(cid)) 
FROM sal_forwarding 
WHERE forwardDate BETWEEN "2011-01-01" AND "2011-11-01" 
GROUP BY f_shop 

我该怎么做才能提高性能? 非常感谢。

回答

1

稍微修改你所拥有的...使用count(*)而不是实际字段。对于DISTINCT,你不需要()。它可能会让你对所有的索引感到困惑。卸下forwardDate与以外的所有其他指数基于(forwardDate,f_shop,CID)(您当前KEY7指数)有一个

SELECT 
     COUNT(*), 
     f_shop, 
     COUNT(DISTINCT cid) 
    FROM 
     sal_forwarding 
    WHERE 
     forwardDate BETWEEN "2011-01-01" AND "2011-11-01" 
    GROUP BY 
     f_shop 

然后,咧嘴一笑,既然没有别的似乎为你工作,尝试投入上记录的预子查询,然后从该综上所述,所以根据您的近1100万条记录它不依赖于任何其它索引页(每个自动增量值隐含的)...

SELECT 
     f_shop, 
     sum(PreQuery.Presum) totalCnt, 
     COUNT(*) dist_cid 
    FROM 
     (select f_shop, cid, count(*) presum 
      from sal_forwarding 
      WHERE forwardDate BETWEEN "2011-01-01" AND "2011-11-01" 
      group by f_shop, cid) PreQuery 
    GROUP BY 
     f_shop 

由于内部预查询是通过F_Shop和C_ID(通过索引进行优化)进行记录和分组的简单计数,现在您将拥有独特的已经汇总的vi一个简单的计数...然后做内部计数的“presum”列的SUM()。再次,尝试和转换表格的另一种选择,希望它适用于你。

+0

你好,查询更新不会提高性能,其他查询正在被其他查询使用,这就是为什么我需要这么多索引。 – user954740

+0

@ user954740,增加了额外的查询选项供您试用。 – DRapp

+0

你好,感谢您的帮助,但其他查询看起来非常复杂,需要一分钟以上。 ;-) – user954740

0

我不认为(forwardDate, f_shop, cid)适合此查询。由于forwardDate列中的范围条件,不比简单的(forwardDate)索引更好。

您可以尝试(f_shop, cid, forwardDate)索引。

+0

你好,这是我的大问题。我从来没有准备好任何有关正确使用索引的好文档。我不知道哪个订单是最好的,为什么。我会尝试你的提示。 – user954740

+0

问题是'(forwardDate,f_shop,cid)'是这个查询的最佳索引,但由于索引第一部分的范围条件,MySQL无法使用它。如果你有'forwardDate ='2011-01-01'',而不是'BETWEEN ...',它会被使用。 –

+0

查询不使用刚刚存在的新索引,它告诉我它是更好的索引。 – user954740