1

我想在 ~5m 行表中找到所有有后继的每小时记录。

我试过了 :

SELECT DISTINCT (date_time)
FROM my_table
JOIN (SELECT DISTINCT (DATE_ADD( date_time, INTERVAL 1 HOUR)) date_offset
      FROM my_table) offset_dates
ON date_time = date_offset

SELECT DISTINCT(date_time)
FROM my_table
WHERE date_time IN (SELECT DISTINCT(DATE_ADD(date_time, INTERVAL 1 HOUR))
                    FROM my_table)

第一个在几秒钟内完成,秒挂几个小时。我可以理解越早越好,但为什么会有如此巨大的性能差距?

- - - - 编辑 - - - - - - - -

这是EXPLAIN两个查询的

id  select_type table       type    possible_keys   key     key_len ref                         rows    Extra
1   PRIMARY     <derived2>  ALL     NULL            NULL    NULL    NULL                        1710    Using temporary
1   PRIMARY     my_table    ref     PRIMARY         PRIMARY 8       offset_dates.date_offset    555     Using index
2   DERIVED     my_table    index   NULL            PRIMARY 13      NULL                        5644204 Using index; Using temporary


id  select_type        table    type    possible_keys   key     key_len ref     rows    Extra
1   PRIMARY            my_table range   NULL            PRIMARY 8       NULL    9244    Using where; Using index for group-by
2   DEPENDENT SUBQUERY my_table index   NULL            PRIMARY 13      NULL    5129983 Using where; Using index; Using temporary
4

4 回答 4

2

我会在两个查询前加上explain,然后比较访问计划的差异。您可能会发现第一个查询查看的行数远少于第二个查询。

但我的预感是 JOIN 比 WHERE 子句更直接地应用。因此,在 WHERE 子句中,您从 获取每条记录my_table,应用算术函数,然后对它们进行排序,因为select distinct通常需要排序,有时它会在内存或磁盘上创建一个临时表。检查的行数可能是每个表大小的乘积。

但是在 JOIN 子句中,很多在 WHERE 子句中被检查和排序的行可能被预先消除了。您最终可能会看到更少的行......并且数据库可能会采取更简单的措施来完成它。

但我认为这篇文章最好地回答了你的问题:SQL fixed-value IN() vs. INNER JOIN performance

于 2013-08-06T16:10:55.993 回答
2

通常,使用连接的查询比使用 的等效查询执行得更好IN (...),因为前者可以利用索引而后者不能;IN必须为可能返回的每一行扫描整个列表。

(请注意,在这种情况下,某些数据库引擎的性能要优于其他数据库引擎;例如,SQL Server可以为两种类型的查询产生同等的性能。)

SELECT您可以通过预先添加EXPLAIN查询并运行它来查看 MySQL 查询优化器打算对给定查询执行的操作。除其他外,这将为您提供引擎必须为查询中的每个步骤检查的行数;将这些计数相乘以获得引擎必须访问的总行数,这可以作为对可能性能的粗略估计。

于 2013-08-06T16:11:22.620 回答
1

对于大型表,'IN' 子句通常很慢。据我记得,对于您打印出的第二条语句 - 它会简单地遍历 my_table 的所有行(除非您在那里有索引)检查每一行是否匹配 WHERE 子句。通常,IN 被视为一组 OR 子句,其中包含所有集合元素。这就是为什么,我认为,使用在 JOIN 查询后台创建的临时表会更快。

以下是一些有用的链接:

索引列上的 MySQL 查询 IN() 子句慢

内连接和 in() 子句性能在哪里?

http://explainextended.com/2009/08/18/passing-parameters-in-mysql-in-list-vs-temporary-table/

于 2013-08-06T16:20:51.537 回答
1

另一件需要考虑的事情是,与 JOIN 相比,使用您的 IN 样式,未来的优化几乎是不可能的。通过连接,您可以添加一个索引,谁知道呢,这取决于数据集,它可能会将速度提高 2、5、10 倍。使用 IN,它将运行该查询。

于 2013-08-06T16:57:09.777 回答