我有大量MySQL表,有数十万行。
我需要在客户表上写一个查询,该表可以了解客户何时可以再次联系。
例如
SELECT 'This week', COUNT(*) FROM customers
WHERE sales_person_id = 1 AND DATEDIFF(NOW(), available_date) < 7
UNION
SELECT 'Next week', COUNT(*) FROM customers
WHERE sales_person_id = 1 AND DATEDIFF(NOW(), available_date) >= 7
AND DATEDIFF(NOW(), available_date) < 14
UNION
... (a few more like this)
在不同的大表上编写了类似的查询后,我注意到将引擎从InnoDB更改为MyISAM大大加快了查询速度(这些表不需要InnoDB,因为它们没有外键检查)。还有什么我可以做的事情来加速这样的计数(除了索引相应的字段)?
答案 0 :(得分:5)
WHERE sales_person_id = 1 AND available_date BETWEEN CURDATE() - INTERVAL 1 WEEK AND CURDATE()
这样做应该让MySQL使用在(sales_person_id, available_date)
列上创建的复合索引(使用EXPLAIN来检查)
答案 1 :(得分:3)
永远不要在多个查询中,你可以在一个查询中做什么。
如果您创建一个具有必要开始和放大的派生表/内联视图结束日期,这可用于使用GROUP BY在单个查询中生成所需结果。 MySQL没有递归函数,因此你必须使用NUMBERS表技巧来生成日期......
创建一个只保存递增数字的表 - 使用auto_increment很容易做到:
DROP TABLE IF EXISTS `example`.`numbers`;
CREATE TABLE `example`.`numbers` (
`id` int(10) unsigned NOT NULL auto_increment,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
使用以下方法填充表格:
INSERT INTO NUMBERS (id)
VALUES (NULL)
...根据需要提供尽可能多的价值。
使用DATE_ADD构建日期列表,根据NUMBERS.id值增加日期。
SELECT x.start_dt,
x.end_dt
FROM (SELECT DATE_ADD(NOW(), INTERVAL n.id - 1 DAY) AS start_dt,
DATE_ADD(NOW(), INTERVAL n.id + 6 DAY) AS end_dt
FROM `numbers` n
WHERE DATE_ADD(NOW(), INTERVAL (n.id - 1) DAY) <= '2011-01-01') x
根据日期时间部分加入您的数据表:
SELECT x.start_dt,
x.end_dt,
COUNT(*) AS num
FROM (SELECT DATE_ADD(NOW(), INTERVAL n.id - 1 DAY) AS start_dt,
DATE_ADD(NOW(), INTERVAL n.id + 6 DAY) AS end_dt
FROM `numbers` n
WHERE DATE_ADD(NOW(), INTERVAL (n.id - 1) DAY) <= '2011-01-01') x
JOIN CUSTOMERS c ON c.available_date BETWEEN x.start_dt
AND x.end_dt
GROUP BY x.start_dt, x.end_dt
不要使用在实际列数据上执行的函数 - IE:DATEDIFF(NOW(), *available_date*)
- 因为数据库不能使用available_date
列上的索引(如果存在),因为数据已经改变了指数值。
答案 2 :(得分:1)
专注于WHERE子句。