【问题标题】:MySQL: Why does an Order By ID runs much slower than Order By other Columns?MySQL:为什么按 ID 排序比按其他列排序慢得多?
【发布时间】:2011-11-26 16:45:01
【问题描述】:

我正在使用 MySQL 5.5.14 版从 500 万行的表中运行以下查询 QUERY 1

SELECT P.ID, P.Type, P.Name, P.cty
     , X(P.latlng) as 'lat', Y(P.latlng) as 'lng'
     , P.cur, P.ak, P.tn, P.St, P.Tm, P.flA, P.ldA, P.flN
     , P.lv, P.bd, P.bt, P.nb
     , P.ak * E.usD as 'usP' 
FROM PIG P 
  INNER JOIN EEL E 
    ON E.cur = P.cur 
WHERE act='1' 
  AND flA >= '1615' 
  AND ldA >= '0' 
  AND yr >= (YEAR(NOW()) - 100) 
  AND lv >= '0' 
  AND bd >= '3' 
  AND bt >= '2' 
  AND nb <= '5' 
  AND cDate >= NOW() 
  AND MBRContains(LineString( Point(39.9097, -2.1973)
                            , Point(65.5130, 41.7480)
                            ), latlng) 
  AND Type = 'g' 
  AND tn = 'l' 
  AND St + Tm - YEAR(NOW()) >= '30' 
HAVING usP BETWEEN 300/2 AND 300 
ORDER BY ak
LIMIT 100;

使用 Index (Type, tn, act, flA),我能够在 800ms 内获得结果。在QUERY 2中,我将ORDER BY 子句更改为lv,我也能够在类似的时间内获得结果。在 QUERY 3 中,我将 ORDER BY 子句更改为 ID,平均 10 次试验,查询时间显着减慢到整整 20 秒

运行EXPLAIN SELECT 语句会产生完全相同的查询执行计划:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: P
         type: range
possible_keys: Index
          key: Index
      key_len: 6
          ref: NULL
         rows: 132478
        Extra: Using where; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: E
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 3
          ref: BS.P.cur
         rows: 1
        Extra: 

我的问题是:为什么在 QUERY 3 中按 ID 排序的速度比其他的慢?

部分表定义如下:

CREATE TABLE `PIG` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `lv` smallint(3) unsigned NOT NULL DEFAULT '0',
  `ak` int(10) unsigned NOT NULL DEFAULT '0',

  PRIMARY KEY (`ID`),
  KEY `id_ca` (`cty`,`ak`),
  KEY `Index` (`Type`, `tn`, `act`, `flA`),
) ENGINE=MyISAM AUTO_INCREMENT=5000001 DEFAULT CHARSET=latin1

CREATE TABLE `EEL` (
  `cur` char(3) NOT NULL,
  `usD` decimal(11,10) NOT NULL,
  PRIMARY KEY (`cur`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

更新:在对各种ORDER BYs 选项进行广泛测试后,我确认恰好是主键的 ID 列是唯一导致查询时间缓慢的列。

【问题讨论】:

  • 不是答案,而是对您的查询/数据库的评论。为了您和他人,请使用相关名称。如果你离开这个应用程序一个月左右,然后回来。您将必须弄清楚每列包含什么。对于这样的论坛上的问题,它没有多大意义。这将需要一些额外的输入,但这不应该有任何问题。
  • @Topener:很抱歉,如果在列名上使用短格式会让您更难理解我的问题。我担心透露申请。希望你能理解;p
  • 在没有ORDER BY 而使用LIMIT 100 的情况下,查询需要运行多长时间?
  • 你能描述一下EEL吗?
  • @radiospiel,是的,HAVING 可以在没有GROUP BY 的情况下使用。您可以在 Stackoverflow 上创建一个单独的问题,而不是在此处发布。

标签: mysql performance query-optimization


【解决方案1】:

来自http://dev.mysql.com/doc/refman/5.6/en/order-by-optimization.html的 MySQL 文档

在某些情况下,MySQL 无法使用索引来解析ORDER BY,尽管它仍然使用索引来查找与WHERE 子句匹配的行。这些案例包括:

。 . .

用于获取行的键与ORDER BY中使用的键不同:

`SELECT * FROM t1 WHERE key2=constant ORDER BY key1;`

这可能无济于事,但是如果将AND ID &gt; 0 添加到WHERE 子句会发生什么?这会导致 MySQL 使用主键进行排序吗?我想值得一试。

(使用 ak 排序似乎很奇怪,因为 ak 甚至没有索引,但这可能是由于 ak 的值较少?)

【讨论】:

  • @Bob:我已经完成了测试。将AND ID &gt; 0 添加到WHERE 子句不会更改查询执行计划。无论排序列如何,返回的行数都应该相同。使用 ak 时 MySQL 的执行速度不会明显变慢,因为只返回了几百行。
【解决方案2】:

如果 WHERE 子句中的条件与 ORDER BY 中的条件不同,或者它不是复合索引的一部分,则排序不会在存储引擎中进行,而是在 MySQL 服务器级别进行,这要慢得多.长话短说,您必须重新排列索引才能同时满足行过滤和排序。

【讨论】:

  • 对于 QUERY 1,ORDER BY 包含 ak,它不在 where 子句中,也不在复合索引中。对于 QUERY 2,ORDER BY 包含 lv,它在 where 子句中,但不在复合索引中。 QUERIES 1 和 2 都很快。你的解释似乎没有回答我的问题。
【解决方案3】:

您可以使用force index(PRIMARY) 试一试,你会在解释查询中看到mysql现在在'order by'时会使用主键索引

【讨论】:

    猜你喜欢
    • 2018-09-20
    • 2021-05-29
    • 1970-01-01
    • 2022-01-16
    • 2011-12-03
    • 1970-01-01
    • 2018-03-12
    • 2023-04-11
    • 2020-06-22
    相关资源
    最近更新 更多