Mysql 如何优化搜索可为空的开始日期或结束日期的SQL查询?

Mysql 如何优化搜索可为空的开始日期或结束日期的SQL查询?,mysql,sql,date,datetime,Mysql,Sql,Date,Datetime,问题:给定一系列可为空的开始和结束日期,优化底部以下查询示例架构的最佳方法是什么: 下面显示添加了空搜索的解释: 1, SIMPLE, s, ALL, date_start_idx,date_end_idx, , , , 6340, Using where; Using temporary; Using filesort MySQL模式示例: 我的猜测是最好的方法如下。首先,在开始和结束时创建索引: 1, SIMPLE, s, range, date_start_idx,date_end_id

问题:给定一系列可为空的开始和结束日期,优化底部以下查询示例架构的最佳方法是什么:

下面显示添加了空搜索的解释:

1, SIMPLE, s, ALL, date_start_idx,date_end_idx, , , , 6340, Using where; Using temporary; Using filesort
MySQL模式示例:


我的猜测是最好的方法如下。首先,在开始和结束时创建索引:

1, SIMPLE, s, range, date_start_idx,date_end_idx, date_end_idx, 6, , 251, Using index condition; Using where; Using temporary; Using filesort
然后使用union all重新表述查询:


我假设您希望选择与日期范围重叠的所有行[2014-11-03 06:00:00,2014-11-10 06:00:00,结束日期是独占的。选择此类记录的查询是:

SELECT * FROM dateranges
WHERE '2014-11-10 06:00:00' > `start`
AND `end` > '2014-11-03 06:00:00'
为了处理空日期,我建议您将日期列设置为非空,并存储不切实际的值,例如1000-01-01表示开始,9999-12-31表示结束,而不是空

话虽如此,您可以使用OR子句检查空值,但仍然可以使用此查询使用索引:

SELECT a.*
FROM dateranges AS a
INNER JOIN dateranges AS b ON a.id = b.id
WHERE ('2014-11-10 06:00:00' > a.`start` OR a.`start` IS NULL)
AND (b.`end` > '2014-11-03 06:00:00' OR b.`end` IS NULL)
此查询可以使用两个索引,因为AND-OR子句是按策略分组的。但是,如果MySQL出于某种原因(例如,由于基数不足)选择不使用索引,则此查询的性能将比无连接版本差得多


还可以在开始日期和结束日期上创建索引。如果在开始日期和结束日期上创建复合索引,那么还应该创建结束日期和开始日期索引。MySQL将根据查询中的固定日期选择其中一个索引。

我认为这不会比原始查询运行得快。而且它肯定也不更清晰。这必须通过n一个大表。+1是的,绝对正确。对IN子句也有效。我自己在SQL Server上使用SELECT MINx FROM WHERE someid IN 1,2的经验不好。我将把这一点添加到原始问题中。起始和结束都有索引。但查询仍然说它使用WHERE子句。@CGSmith105…MySQL需要一个相对较大的表来使用索引。如果您的表只有几百行,甚至几千行,它可能会发现扫描速度更快。@GordonLinoff MySQL切换是有意义的。您还会使用索引的并集吗?在第一个条件中添加“start is not null”和“end is not null”将有助于消除所有的null行。有什么作用此查询搜索?包含在指定日期内的记录或与指定日期重叠/冲突的记录?@SalmanA此查询返回名称的id以用于内容搜索。某些名称可以有内容的开始时间,但没有结束时间。
create index idx_dateranges_start_end on dateranges(start, end)
SELECT * FROM dateranges WHERE ('2014-11-10 05:59:59' > `start` AND
                                '2014-11-03 06:00:00' <= `end` AND
                                '2014-11-03 06:00:00' < `start`
                               )
UNION ALL
SELECT * FROM dateranges WHERE ('2014-11-03 06:00:00' >= `start` AND `end` is null)
UNION ALL
SELECT * FROM dateranges WHERE ('2014-11-10 05:59:59' <= `end` AND `start` is null);
SELECT *
FROM dateranges
WHERE ('2014-11-10 05:59:59' > `start` AND '2014-11-03 06:00:00' <= `end`)
SELECT * FROM dateranges
WHERE '2014-11-10 06:00:00' > `start`
AND `end` > '2014-11-03 06:00:00'
SELECT a.*
FROM dateranges AS a
INNER JOIN dateranges AS b ON a.id = b.id
WHERE ('2014-11-10 06:00:00' > a.`start` OR a.`start` IS NULL)
AND (b.`end` > '2014-11-03 06:00:00' OR b.`end` IS NULL)