优化MYSQL排名mod查询

时间:2017-06-26 16:17:22

标签: mysql sql optimization mod

我遇到了一些重大问题,这些问题会导致数据集变细,从而及时返回结果。我已经粘贴在此表的索引下面(我认为这足以提高速度)以及查询的逻辑。

我试过的一件事是删除" ORDER BY"在内部查询,但实际上并没有改善它的时间,以及清理我选择的一些额外的不需要的列,这改善了时间,但没有使它"足够快"。

SELECT unix_date, price FROM
(SELECT @row := @row +1 as row_num, unix_date, price 
FROM (SELECT @row:=0, unix_date, price FROM 
price_data WHERE created_date >= '2017-03-26 00:00:00' AND created_date 
<= '2017-06-26 23:59:59' AND currency= 'USD' ORDER BY unix_date DESC) 
AS p) AS d
WHERE MOD(row_num, 288) = 1;

此查询的重点只是尝试返回价格数据点的结果集(unix时间戳,价格),但将其细化为仅返回每288(或X)个数据点。这个表目前很小(总行数:198109),所以我很难理解为什么查询需要这么长时间才能返回。

以下是目前表格中的索引:

| Table              | Non_unique | Key_name     | Seq_in_index | 
Column_name  | Collation | Cardinality | Sub_part | Packed | Null | 
Index_type | Comment | Index_comment |
+--------------------+------------+--------------+--------------+------
--------+-----------+-------------+----------+--------+------+---------
---+---------+---------------+
| price_data |          0 | PRIMARY      |            1 | 
unix_date    | A         |      200002 |     NULL | NULL   |      | 
BTREE      |         |               |
| price_data |          0 | PRIMARY      |            2 | 
currency     | A         |      200002 |     NULL | NULL   |      | 
BTREE      |         |               |
| price_data |          1 | created_date |            1 | 
created_date | A         |      200002 |     NULL | NULL   |      | 
BTREE      |         |               |
| price_data |          1 | price        |            1 | price        
| A         |      200002 |     NULL | NULL   | YES  | BTREE      |         
|               |
+--------------------+------------+--------------+--------------+------
--------+-----------+-------------+----------+--------+------+---------
---+---------+--

根据我的建议我添加了创建表:

  CREATE TABLE `price_data` (
  `created_date` datetime NOT NULL,
  `unix_date` int(11) NOT NULL,
  `currency` varchar(255) NOT NULL DEFAULT '',
  `price` decimal(10,6) DEFAULT NULL,
  PRIMARY KEY (`unix_date`,`currency`),
  KEY `created_date` (`created_date`),
  KEY `price` (`price`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 |

非常感谢有关如何提高此查询速度的任何建议。

编辑:问题是否与此查询的最终WHERE一致,实际上是针对&#34;假列&#34; row_num是从前面的内部查询派生的,因此它本身并没有真正的索引?因此,当WHERE正在评估它时,正常索引列的速度不是这样吗?

1 个答案:

答案 0 :(得分:2)

将主键更改为货币unix_date。由于您具有货币的相等条件和unix_date的范围条件,因此应首先将具有相等条件的列放入。然后,unix_date和ORDER BY上的范围条件都应该使用主键顺序。

将条件应用于unix_date,而不是create_date,以使其使用主键索引。

您必须使用派生表子查询,但不必使用两个嵌套级别的子查询。

SELECT row_num, unix_date, price
FROM (
    SELECT @row := @row + 1 AS row_num, unix_date, price
    FROM (SELECT @row := 0) AS _init
    CROSS JOIN price_data
    WHERE currency = 'USD' 
     AND unix_date BETWEEN UNIX_TIMESTAMP('2017-03-26 00:00:00') 
                       AND UNIX_TIMESTAMP('2017-06-26 23:59:59')
    ORDER BY unix_timestamp DESC
) AS t
WHERE MOD(row_num, 288) = 1

您应该学会use EXPLAIN来帮助您分析索引使用情况。

您可能还需要我的演示文稿How to Design Indexes, Really和视频:https://www.youtube.com/watch?v=ELR7-RdU9XU

MySQL 8.0应该有窗口函数,所以有时候要在明年查找。