【问题标题】:MySQL query with less than and ORDER BY DESCMySQL查询小于和ORDER BY DESC
【发布时间】:2015-05-14 07:23:40
【问题描述】:

我正在处理一组相当大的数据,并试图从四个不同数据的每个组合中创建一个查询。所有这些部分组合起来形成了惊人的 122,000,000 行。然后,我试图找到一个小于某个数量的权重,并按另一个值从高到低排序。

我可以使用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 |

【问题讨论】:

    标签: mysql indexing sql-order-by where where-clause


    【解决方案1】:

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

    1. 所有找到weight &lt; x (WHERE) 的行(使用任何以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”不重要。

    【讨论】:

    • 我认为查询计划会自动执行此操作?首先按
    • 查看EXPLAINs。您可能会发现有些使用索引,有些则不使用。优化器无法准确地在两者之间做出决定。我怀疑你看到了一个选择错误的案例。
    • 2 个范围(体重和身高)不能同时使用。想象一个按字母顺序排列的人员列表——按姓氏和名字排序。现在假设你想找到所有有我姓名缩写的人(J.,R.)INDEX(last, first) 没有用,它只会扫描所有last LIKE 'J%',检查每个R。你需要一个二维索引。我见过的最接近的是latitude/longitude search,它可能适用于您的应用程序。
    • 我明天会试试你修改后的加入。如果这不是解决方案,我还有其他一些想法。主要思想是重量不需要是小数。但是,由于这似乎不是瓶颈,因此可能是毫无意义的优化。我会回来报告的!
    • 是的,我怀疑 DECIMALFLOAT 等是否重要。你有smallint(2);您只需要 2 位数字吗? SMALLINT 是 2 个字节; TINYINT 是 1 个字节(范围 -128..127)或 TINYINT UNSIGNED (0..255)。
    猜你喜欢
    • 2013-09-20
    • 2015-02-26
    • 1970-01-01
    • 2011-12-22
    • 2012-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多