2015-05-14 68 views
0

我正在做一些相当大的一组数据,并试图从四个不同的数据组合的每个组合创建一个查询。所有这些组合形成了惊人的1.22亿行。然后,我试图找到一个小于一定数量的权重,并按照从最高到最低的另一个值进行排序。MySQL查询与小于和ORDER BY DESC

我可以使用weight < x没问题。

我可以使用weight < x order by height ASC没问题。

当x位于上下两端时,我甚至可以使用weight < x order by height DESC。但是一旦它开始蔓延到中间,它就会很快从几秒钟上升到几分钟,直到“我不会等那么久。”

有什么想法? (该名称已经更改,但种类却没有)

的创建:

CREATE TABLE combinations (
    id bigint(20) unsigned NOT NULL auto_increment, 
    up smallint(2) NOT NULL, 
    left smallint(2) NOT NULL, 
    right smallint(2) NOT NULL, 
    down smallint(2) NOT NULL, 
    weight decimal(5,1) NOT NULL, 
    width smallint(3) NOT NULL, 
    forward decimal(6,2) NOT NULL, 
    backwards decimal(5,2) NOT NULL, 
    in decimal(7,2) NOT NULL, 
    out smallint(3) NOT NULL, 
    height smallint(3) NOT NULL, 
    diameter decimal(7,2) NOT NULL, 
    PRIMARY KEY (id) 
); 

指数

ALTER TABLE combinations ADD INDEX weight_and_height(weight,height); 

查询

SELECT * FROM combinations WHERE weight < 20 ORDER BY height DESC limit 0,5; 

的解释

| id | select type | table  | type | possible_keys  | key    | key_len | ref | rows | extra  | 
| 1 | simple  | combinations | index | weight_and_height | weight_and_height | 5  | NULL | 10 | using where | 

回答

0

您的索引仅用于过滤weight。下面是步骤:

  1. 所有行与weight < xWHERE)被发现(使用任何索引开始weight
  2. 即组进行排序(ORDER BY height ...
  3. 0(OFFSET)行被跳过;
  4. 5(LIMIT)行已交付。

潜在昂贵的部分是第1步大概是在你的榜样“20”是在列表得很早。实际上EXPLAIN估计该集合只有10行。对于x较大的值,第1步需要更长的时间。这是不可避免的。

全部来自步骤1的行被处理;因此,步骤2的时间也会变化。 (5.6有部分组合步骤2,3,4的额外优化。)

您确实在做SELECT *?例如,如果您只想要SELECT id,那么INDEX(weight, height, id)将运行得更快,因为可以在索引中完全执行查询。

如果你真的需要你提到的查询,那么这将一定程度上更快地运行:

SELECT c.* 
    FROM (
     SELECT id FROM combinations 
      WHERE weight < 20 ORDER BY height DESC limit 0,5 
     ) ids 
    JOIN combinations AS c USING(id) 
    ORDER BY height DESC; 

注:

  • 子查询“使用索引”前面已经提到。
  • 只有5行由子查询传递。
  • SELECT只有5行处理。
  • id被索引(因为它是PRIMARY KEY),所以JOIN是有效的。
  • (Re:标题)“小于”和“DESC”不重要。
+0

我认为查询计划会自动做到这一点?首先通过 johnrom

+0

看看'EXPLAINs'。您可能会发现有些使用索引,有些则不使用。优化器无法准确地做出两者之间的决定。我怀疑你正在看到一个它做出错误选择的案例。 –

+0

2个范围(重量和高度)不能同时使用。想象一下按字母顺序排列的人员列表 - 按姓氏和名字排序。现在假设你想找到所有拥有我的姓名缩写的人(J.,R.)。'INDEX(last,first)'没有用,它只是简单地扫描所有'last LIKE'J%''检查每个一个用于'R'。你需要一个2D索引。我看到的最接近的是[纬度/经度搜索](http://mysql.rjweb.org/doc.php/latlng),它可能适用于您的应用程序。 –