优化sql查询执行内部比较

时间:2011-08-30 16:13:51

标签: mysql sql myisam

我有以下查询,有点贵(目前为500毫秒):

SELECT * FROM events AS e, event_dates AS ed 
WHERE e.id=ed.event_id AND ed.start >= DATE(NOW()) 
GROUP BY e.modified_datetime, e.id 
ORDER BY e.modified_datetime DESC,e.created_datetime DESC 
LIMIT 0,4

我一直在努力想出如何加快速度,并注意到将ed.start >= DATE(NOW())更改为ed.start = DATE(NOW())会在20ms内运行查询。任何人都可以帮助我加快这个日期比较的方法吗?在运行查询之前计算DATE(NOW())会有帮助吗?

编辑:这有帮助,使用EXPLAIN语句

BEFORE
table=event_dates
type=range
rows=25962
ref=null
extra=using where; Using temporary; Using filesort

AFTER
table=event_dates
type=ref
rows=211
ref=const
extra=Using temporary; Using filesort

5 个答案:

答案 0 :(得分:2)

SELECT * FROM events AS e
INNER JOIN event_dates AS ed ON (e.id=ed.event_id)
WHERE ed.start >= DATE(NOW()) 
GROUP BY e.modified_datetime, e.id 
ORDER BY e.modified_datetime DESC,e.created_datetime DESC 
LIMIT 0,4

备注

  1. 请不要使用隐式SQL '89语法,它是一种SQL反模式。
  2. 确保您在联接中使用的所有字段都有索引,包括where,in group by和order by子句。
  3. 不要select * (另一种反模式),明确说明您需要的字段。
  4. 尝试使用InnoDB而不是MyISAM,InnoDB为select语句提供了更多优化技巧,特别是如果您只选择索引字段。
  5. 对于MyISAM表,请尝试使用REPAIR TABLE tablename
  6. 对于InnoDB而言,这不是一个选项,但是将表格类型从MyISAM强制转移到InnoDB显然会强制完全重建表和所有索引。
  7. 分组隐式按ASC顺序对行进行排序,尝试将组更改为group by -e.modified_datetime, e.id以最小化order by子句所需的重新排序。 (不确定这一点,想知道结果)

答案 1 :(得分:2)

作为参考,使用,表示连接是不好的做法,并且导致执行计划不佳。

SELECT
  *
FROM
  events        AS e
INNER JOIN
  event_dates   AS ed
    ON e.id=ed.event_id
WHERE
  ed.start >= DATE(NOW())
GROUP BY
  e.modified_datetime,
  e.id 
ORDER BY
  e.modified_datetime DESC,
  e.created_datetime DESC 
LIMIT 0,4

为什么=>=更快只是因为>=Range的值,而不是非常具体的值。这就像是说“从第101页开始,让我从书中获取页面”而不是“让我第101页”。根据定义,它更加密集,特别是当您的查询涉及聚合和排序更多记录时。

在优化方面,您最好的选择是确保相关索引......

event_dates:
- start上的索引应该足够了

事件:
- id上的索引将显着改善联接效果 - 将modified_datetimecreated_datetime添加到该索引可能会有所帮助

答案 2 :(得分:2)

您正在分组和搜索的字段可能缺少索引。请向我们提供:SHOW INDEXES FROM eventsSHOW INDEXES FROM event_dates

如果没有索引,则可以添加它们:

ALTER TABLE events ADD INDEX(modified_datetime);
ALTER TABLE events ADD INDEX(created_datetime);
ALTER TABLE event_dates ADD INDEX(start);

ALTER TABLE events ADD INDEX(modified_datetime); ALTER TABLE events ADD INDEX(created_datetime); ALTER TABLE event_dates ADD INDEX(start);

还要确保在字段中显示它们。但在这里你可能希望将它们作为主键。

答案 3 :(得分:1)

提前计算DATE(NOW())不会对性能产生任何影响。它只计算一次(不是每行)。但是您有2个不同的查询(一个使用>=,另一个使用=)。看起来很自然,第一个(>=)需要更长的时间来执行,因为它返回了更多的行。此外,与使用=的查询相比,它可能决定使用不同的执行计划,例如,全表扫描而不是索引搜索/扫描

答案 4 :(得分:0)

你可以做这样的事情

DECLARE @CURRENTDATE AS DATETIME 
SET @CURRENTDATE = GETDATE()

然后更改您的代码以使用

@CURRENTDATE variable.... "e.start >= @CURRENTDATE