【问题标题】:MySQL/memSQL not using index on BETWEEN join conditionMySQL/memSQL 未在 BETWEEN 连接条件上使用索引
【发布时间】:2017-08-28 02:56:06
【问题描述】:

我们有两张桌子:

  • dates 表,其中包含过去 10 年和未来 10 年每天的一个日期。
  • 具有以下列的states 表:start_dateend_datestate

我们运行的查询如下所示:

SELECT dates.date, COUNT(*)
FROM dates
JOIN states
ON dates.date BETWEEN states.start_date AND states.end_date
WHERE dates.date BETWEEN '2017-01-01' AND '2017-01-31'
GROUP BY dates.date
ORDER BY dates.date;

根据查询计划,memSQL 没有在 JOIN 条件上使用索引,这使得查询速度变慢。有没有办法可以在 JOIN 条件上使用索引?

我们在 dates.date、states.start_date、states.end_date、(states.start_date, states.end_date) 上尝试了 memSQL 跳过列表索引

表格和解释:

CREATE TABLE `dates` (
  `date` date DEFAULT NULL,
  KEY `date_index` (`date`)
)

CREATE TABLE `states` (
  `start_date` datetime DEFAULT NULL,
  `end_date` datetime DEFAULT NULL,
  `state` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  KEY `start_date` (`start_date`),
  KEY `end_date` (`end_date`),
  KEY `start_date_end_date` (`start_date`,`end_date`),
)

+-----------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                             |
+-----------------------------------------------------------------------------------------------------------------------------------------------------+
| GatherMerge [remote_0.date] partitions:all est_rows:96 alias:remote_0                                                                               |
| Project [r2.date, CAST(COALESCE($0,0) AS SIGNED) AS `COUNT(*)`] est_rows:96                                                                         |
| Sort [r2.date]                                                                                                                                      |
| HashGroupBy [SUM(r2.`COUNT(*)`) AS $0] groups:[r2.date]                                                                                             |
| TableScan r2 storage:list stream:no                                                                                                                 |
| Repartition [r1.date, `COUNT(*)`] AS r2 shard_key:[date] est_rows:96 est_select_cost:26764032                                                       |
| HashGroupBy [COUNT(*) AS `COUNT(*)`] groups:[r1.date]                                                                                               |
| Filter [r1.date <= states.end_date]                                                                                                                 |
| NestedLoopJoin                                                                                                                                      |
| |---IndexRangeScan drstates_test.states, KEY start_date (start_date) scan:[start_date <= r1.date] est_table_rows:123904 est_filtered:123904         |
| TableScan r1 storage:list stream:no                                                                                                                 |
| Broadcast [dates.date] AS r1 distribution:tree est_rows:96                                                                                          |
| IndexRangeScan drstates_test.dates, KEY date_index (date) scan:[date >= '2017-01-01' AND date <= '2017-01-31'] est_table_rows:18628 est_filtered:96 |
+-----------------------------------------------------------------------------------------------------------------------------------------------------+

【问题讨论】:

  • 你能发布解释和表格声明吗?
  • @Kickstart 添加。
  • 您在 DATE 上加入 DATETIME,这可能允许 MySQL 忽略索引(而是倾向于在 WHERE 子句中的日期上使用索引)。如果您需要日期表(如果您使用 LEFT OUTER JOIN,则假定为空天),那么您可以尝试添加开始和结束日期时间字段并加入这些字段以避免转换?
  • @Kickstart 谢谢。我继续创建了一个 datetimes 表来替换 dates 表,以便比较发生在相同的数据类型上 - EXPLAIN 的输出看起来相同。你能解释一下try adding a start and end date time fields and joining on those to avoid the conversion 的意思吗?值得注意的是,这不是 MySQL,而是 memSQLdocs.memsql.com/docs
  • 如果您不使用 MySQL,请删除该标签。

标签: mysql query-optimization sqlperformance singlestore


【解决方案1】:
ON dates.date BETWEEN states.start_date
                  AND states.end_date

本质上是不可优化的。执行此测试的唯一实用方法是繁琐地测试每一行。

如果您使用 MySQL 并且不需要 dates 表,请考虑从

SELECT  *
    FROM  states
    WHERE  start_date >= '2017-01-01'
      AND  end_date    < '2017-01-01' + INTERVAL 1 MONTH 

请注意,这适用于 DATEDATETIME 数据类型的任意组合。

由于我不清楚最终目标,所以我不清楚下一步该做什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多