优化慢速MySQL选择查询

马蒂斯·德·琼

编辑:在研究了这里的一些答案和数小时的研究后,我的团队得出的结论是,除了我们能够实现的4.5秒之外,最有可能无法对其进行优化(除非可以对offers_clicks进行分区,但是会有一些丑陋的副作用)。最终,经过大量的头脑风暴,我们决定拆分两个查询,创建两组用户ID(一组来自users表,一组来自offer_clicks),并将它们与Python中的set进行比较。用户表中的一组ID仍然是从SQL中提取的,但是我们决定将offer_clicks移至Lucene并在其之上添加一些缓存,因此现在是从中提取另一组ID的地方。最终结果是使用缓存的时间减少到大约半秒,不使用缓存的时间减少到0.9s。

原始文章的开始:我无法优化查询。查询的第一个版本很好,但是在第二个查询中加入offers_clicks的那一刻,查询就变得很慢。“用户”表包含1000万行,“ offs_clicks”包含5300万行。

可接受的表现:

SELECT count(distinct(users.id)) AS count_1
FROM users USE index (country_2)
WHERE users.country = 'US'
  AND users.last_active > '2015-02-26';
1 row in set (0.35 sec)

坏:

SELECT count(distinct(users.id)) AS count_1
FROM offers_clicks USE index (user_id_3), users USE index (country_2)
WHERE users.country = 'US'
  AND users.last_active > '2015-02-26'
  AND offers_clicks.user_id = users.id
  AND offers_clicks.date > '2015-02-14'
  AND offers_clicks.ranking_score < 3.49
  AND offers_clicks.ranking_score > 0.24;
1 row in set (7.39 sec)

无需指定任何索引(甚至更差)的外观如下:

SELECT count(distinct(users.id)) AS count_1
FROM offers_clicks, users
WHERE users.country IN ('US')
  AND users.last_active > '2015-02-26'
  AND offers_clicks.user_id = users.id
  AND offers_clicks.date > '2015-02-14'
  AND offers_clicks.ranking_score < 3.49
  AND offers_clicks.ranking_score > 0.24;
1 row in set (17.72 sec)

说明:

explain SELECT count(distinct(users.id)) AS count_1 FROM offers_clicks USE index (user_id_3), users USE index (country_2) WHERE users.country IN ('US') AND users.last_active > '2015-02-26' AND offers_clicks.user_id = users.id AND offers_clicks.date > '2015-02-14' AND offers_clicks.ranking_score < 3.49 AND offers_clicks.ranking_score > 0.24;
+----+-------------+---------------+-------+---------------+-----------+---------+------------------------------+--------+--------------------------+
| id | select_type | table         | type  | possible_keys | key       | key_len | ref                          | rows   | Extra                    |
+----+-------------+---------------+-------+---------------+-----------+---------+------------------------------+--------+--------------------------+
|  1 | SIMPLE      | users         | range | country_2     | country_2 | 14      | NULL                         | 245014 | Using where; Using index |
|  1 | SIMPLE      | offers_clicks | ref   | user_id_3     | user_id_3 | 4       | dejong_pointstoshop.users.id | 270153 | Using where; Using index |
+----+-------------+---------------+-------+---------------+-----------+---------+------------------------------+--------+--------------------------+

在不指定任何索引的情况下进行解释:

mysql> explain SELECT count(distinct(users.id)) AS count_1 FROM offers_clicks, users WHERE users.country IN ('US') AND users.last_active > '2015-02-26' AND offers_clicks.user_id = users.id AND offers_clicks.date > '2015-02-14' AND offers_clicks.ranking_score < 3.49 AND offers_clicks.ranking_score > 0.24;
+----+-------------+---------------+-------+------------------------------------------------------------------------+-----------+---------+------------------------------+--------+--------------------------+
| id | select_type | table         | type  | possible_keys                                                          | key       | key_len | ref                          | rows   | Extra                    |
+----+-------------+---------------+-------+------------------------------------------------------------------------+-----------+---------+------------------------------+--------+--------------------------+
|  1 | SIMPLE      | users         | range | PRIMARY,last_active,country,last_active_2,country_2                    | country_2 | 14      | NULL                         | 221606 | Using where; Using index |
|  1 | SIMPLE      | offers_clicks | ref   | user_id,user_id_2,date,date_2,date_3,ranking_score,user_id_3,user_id_4 | user_id_2 | 4       | dejong_pointstoshop.users.id |      3 | Using where              |
+----+-------------+---------------+-------+------------------------------------------------------------------------+-----------+---------+------------------------------+--------+--------------------------+

这是我尝试过的很多索引,但并没有取得太大的成功:

+---------------+------------+-----------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table         | Non_unique | Key_name                    | Seq_in_index | Column_name     | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------+------------+-----------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| offers_clicks |          1 | user_id_3                   |            1 | user_id         | A         |         198 |     NULL | NULL   |      | BTREE      |         |               |
| offers_clicks |          1 | user_id_3                   |            2 | ranking_score   | A         |         198 |     NULL | NULL   |      | BTREE      |         |               |
| offers_clicks |          1 | user_id_3                   |            3 | date            | A         |         198 |     NULL | NULL   |      | BTREE      |         |               |
| offers_clicks |          1 | user_id_2                   |            1 | user_id         | A         |    17838712 |     NULL | NULL   |      | BTREE      |         |               |
| offers_clicks |          1 | user_id_2                   |            2 | date            | A         |    53516137 |     NULL | NULL   |      | BTREE      |         |               |
| offers_clicks |          1 | user_id_4                   |            1 | user_id         | A         |         198 |     NULL | NULL   |      | BTREE      |         |               |
| offers_clicks |          1 | user_id_4                   |            2 | date            | A         |         198 |     NULL | NULL   |      | BTREE      |         |               |
| offers_clicks |          1 | user_id_4                   |            3 | ranking_score   | A         |         198 |     NULL | NULL   |      | BTREE      |         |               |
| users         |          1 | country_2                   |            1 | country         | A         |          14 |     NULL | NULL   |      | BTREE      |         |               |
| users         |          1 | country_2                   |            2 | last_active     | A         |     8048529 |     NULL | NULL   |      | BTREE      |         |               |

简化的用户架构:

+---------------------------------+---------------+------+-----+---------------------+----------------+
| Field                           | Type          | Null | Key | Default             | Extra          |
+---------------------------------+---------------+------+-----+---------------------+----------------+
| id                              | int(11)       | NO   | PRI | NULL                | auto_increment |
| country                         | char(2)       | NO   | MUL |                     |                |
| last_active                     | datetime      | NO   | MUL | 2000-01-01 00:00:00 |                |

简化的优惠点击模式:

+-----------------+------------------+------+-----+---------------------+----------------+
| Field           | Type             | Null | Key | Default             | Extra          |
+-----------------+------------------+------+-----+---------------------+----------------+
| id              | int(11)          | NO   | PRI | NULL                | auto_increment |
| user_id         | int(11)          | NO   | MUL | 0                   |                |
| offer_id        | int(11) unsigned | NO   | MUL | NULL                |                |
| date            | datetime         | NO   | MUL | 0000-00-00 00:00:00 |                |
| ranking_score   | decimal(5,2)     | NO   | MUL | 0.00                |                |
戈登·利诺夫

这是您的查询:

SELECT count(distinct u.id) AS count_1
FROM offers_clicks oc JOIN
     users u
     ON oc.user_id = u.id
WHERE u.country IN ('US') AND u.last_active > '2015-02-26' AND
      oc.date > '2015-02-14' AND
      oc.ranking_score > 0.24 AND oc.ranking_score < 3.49;

首先,count(distinct)您可以考虑将查询写成:

SELECT count(*) AS count_1
FROM users u
WHERE u.country IN ('US') AND u.last_active > '2015-02-26' AND
      EXISTS (SELECT 1
              FROM offers_clicks oc
              WHERE oc.user_id = u.id AND
                    oc.date > '2015-02-14' AND
                    oc.ranking_score > 0.24 AND oc.ranking_score < 3.49
             )

然后,此查询的最佳索引是:users(country, last_active, id)offers_clicks(user_id, date, ranking_score)offers_clicks(user_id, ranking_score, date)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

MySQL“ NOT IN”查询优化

来自分类Dev

MySQL MAX查询优化

来自分类Dev

慢IN()MySQL查询优化

来自分类Dev

MySQL优化庞大的查询

来自分类Dev

MySQL查询优化与调试

来自分类Dev

mysql查询优化任务

来自分类Dev

LINQ查询优化用于慢速分组

来自分类Dev

优化慢速索引的MySql查询

来自分类Dev

MySQL-IN(...)优化问题内的“选择”查询(=>层次查询)

来自分类Dev

MySQL优化器在查询中选择错误的表顺序

来自分类Dev

优化慢速LINQ查询

来自分类Dev

改善慢速MySQL查询

来自分类Dev

MYSQL-索引和优化选择查询

来自分类Dev

laravel MySQL查询优化

来自分类Dev

带有子选择的慢速查询

来自分类Dev

如何以慢速排序依据优化MYSQL查询

来自分类Dev

如何优化MySQL选择查询或使其更快

来自分类Dev

如何使用多个选择查询优化UNION mysql查询?

来自分类Dev

MySQL优化慢速查询与解释

来自分类Dev

使用EF进行总和的慢速mysql查询

来自分类Dev

MSSQL选择查询优化

来自分类Dev

优化慢速索引的MySql查询

来自分类Dev

MySQL-IN(...)优化问题内的“选择”查询(=>分层查询)

来自分类Dev

使用EXPLAIN输出优化慢速MySQL查询

来自分类Dev

MySQL慢速SELECT查询

来自分类Dev

MySQL选择查询需要一些优化

来自分类Dev

如何优化MySQL多表选择查询?

来自分类Dev

使用 UNION 和 DISTINCT 优化 MySQL 选择查询

来自分类Dev

优化选择不同的查询