【问题标题】:Rewriting this subquery?重写这个子查询?
【发布时间】:2010-10-04 21:33:19
【问题描述】:

我正在尝试构建一个新表,以使现有表中的值不包含在另一个表中(但显然以下检查是否包含)。以下是我的表结构:

mysql> explain t1;
+-----------+---------------------+------+-----+---------+-------+
| Field     | Type                | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+-------+
| id        | int(11)             | YES  |     | NULL    |       | 
| point     | bigint(20) unsigned | NO   | MUL | 0       |       | 
+-----------+---------------------+------+-----+---------+-------+

mysql> explain whitelist;
+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| id          | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment | 
| x           | bigint(20) unsigned | YES  |     | NULL    |                | 
| y           | bigint(20) unsigned | YES  |     | NULL    |                | 
| geonetwork  | linestring          | NO   | MUL | NULL    |                | 
+-------------+---------------------+------+-----+---------+----------------+

我的查询如下所示:

SELECT point 
  FROM t1 
 WHERE EXISTS(SELECT source 
                FROM whitelist 
               WHERE MBRContains(geonetwork, GeomFromText(CONCAT('POINT(', t1.point, ' 0)'))));

解释:

    +----+--------------------+--------------------+-------+-------------------+-----------+---------+------+------+--------------------------+
| id | select_type        | table              | type  | possible_keys     | key       | key_len | ref  | rows | Extra                    |
+----+--------------------+--------------------+-------+-------------------+-----------+---------+------+------+--------------------------+
|  1 | PRIMARY            | t1                 | index | NULL              | point     | 8       | NULL | 1001 | Using where; Using index | 
|  2 | DEPENDENT SUBQUERY | whitelist          | ALL   | _geonetwork       | NULL      | NULL    | NULL | 3257 | Using where              | 
+----+--------------------+--------------------+-------+-------------------+-----------+---------+------+------+--------------------------+

查询在 t1 中执行 1000 条记录需要 6 秒,这对我来说是不可接受的。如果我没有要加入的列,如何使用 Joins 重写此查询(或者如果存在更快的方法)?我猜在最坏的情况下,即使是存储过程也是可以接受的。我的目标是最终创建一个包含 t1 条目的新表。有什么建议吗?

【问题讨论】:

  • 地理网络上是否有空间索引?如果没有,那么添加一个应该会有所帮助。
  • @YWE:是的。解释命令中显示的 MUL 用于空间索引。
  • 只是好奇,你最终做了什么来解决你的问题?

标签: sql mysql database query-optimization


【解决方案1】:

除非查询优化器失败,否则WHERE EXISTS 构造应该产生与带有GROUP 子句的连接相同的计划。查看优化MBRContains(geonetwork, GeomFromText(CONCAT('POINT(', t1.point, ' 0)')))),这可能是您的查询花费所有时间的地方。我对此没有任何建议,但这是您使用JOIN 编写的查询:

Select t1.point
from t1
join whitelist on MBRContains(whitelist.geonetwork, GeomFromText(CONCAT('POINT(', t1.point, ' 0)'))))
group by t1.point
;

或获取 t1 中不在白名单中的点:

Select t1.point
from t1
left join whitelist on MBRContains(whitelist.geonetwork, GeomFromText(CONCAT('POINT(', t1.point, ' 0)'))))
where whitelist.id is null
;

【讨论】:

  • 它给了我大约相同的执行时间,除了在解释语句的 Extra 列中,它提到:Range checked for each record (index mp: 0x2); Not exists
【解决方案2】:

这似乎是去规范化 t1 可能是有益的情况。添加一个值为GeomFromText(CONCAT('POINT(', t1.point, ' 0)'))GeomFrmTxt 列可以加快您已有的查询速度。

【讨论】:

  • 我的问题是这种方法需要两次通过:一次将列添加到 t1,另一次过滤它及其额外数据。我的实际表包含十亿条记录,因此向其中添加更多数据会使事情变得非常糟糕。我想充分利用索引并一次性完成。
  • 我想我的评论的意思是在创建时添加该行,而不是在查询时。总体而言,您将节省服务器上的处理时间,因为您只需计算一次 GeomFromText,而不是每次运行此查询时。也许您存储我建议的列并摆脱点列:-) 我确定可能不是一个选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-15
  • 2016-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多