我有一个包含大约 1 亿条记录的大表,字段为 start_date
和 end_date
,类型为 DATE
。我需要检查某些日期范围内的重叠次数,比如 2013-08-20
和 2013-08-30
之间,所以我使用。
SELECT COUNT(*) FROM myTable WHERE end_date >= '2013-08-20'
AND start_date <= '2013-08-30'
日期列已编入索引。
重要的一点是,我正在搜索重叠的日期范围总是在未来,而表中记录的主要部分是过去的(比如大约 97-99 百万)。
那么,如果我添加一个列 is_future - TINYINT
,这个查询会更快吗,所以,通过只检查这样的条件
SELECT COUNT(*) FROM myTable WHERE is_future = 1
AND end_date >= '2013-08-20' AND start_date <= '2013-08-30'
它将排除其余 9700 万条左右的记录,并仅检查其余 1-3 百万条记录的日期条件?
我用的是MySQL
谢谢
编辑
mysql 引擎是 innodb,但是如果说是 MyISAM 就很重要了
这里是创建表
CREATE TABLE `orders` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`title`
`start_date` date DEFAULT NULL,
`end_date` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
编辑 2 @Robert Co 回答后
对于这种情况,分区看起来是个好主意,但它不允许我基于 is_future
字段创建分区,除非我将其定义为主键,否则我应该删除我的主要主键- id,我做不到。那么,如果我把那个字段定义为主键,那么有没有分区的意思,如果我用is_future
字段作为主键来搜索,是不是已经很快了。
编辑 3 我需要使用它的实际查询是选择在该日期范围内有一些空位的餐厅
SELECT r.id, r.name, r.table_count
FROM restaurants r
LEFT JOIN orders o
ON r.id = o.restaurant_id
WHERE o.id IS NULL
OR (r.table_count > (SELECT COUNT(*)
FROM orders o2
WHERE o2.restaurant_id = r.id AND
end_date >= '2013-08-20' AND start_date <= '2013-08-30'
AND o2.status = 1
)
)
解决方案 经过更多的研究和测试,在我的案例中计算行数的最快方法是再添加一个条件,start_date 大于当前日期(因为搜索的日期范围总是在未来)
SELECT COUNT(*) FROM myTable WHERE end_date >= '2013-09-01'
AND start_date >= '2013-08-20' AND start_date <= '2013-09-30'
还需要有一个索引 - 带有 start_date 和 end_date 字段(谢谢@symcbean)。 结果,10m 行表的执行时间从 7 秒变成了 0.050 秒。
解决方案 2(@Robert Co) 在这种情况下分区也有效! - 也许这是比索引更好的解决方案。或者它们可以一起应用。
谢谢
最佳答案
这是一个完美的用例 table partitioning .如果 Oracle INTERVAL 特性适用于 MySQL,那么它只会更加出色。
关于mysql - 按日期搜索 mysql 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18430199/