在mysql上优化查询sql

时间:2015-03-13 14:12:13

标签: mysql sql indexing

我有这样的查询:

 DELETE FROM doublon  WHERE id in 
( Select id  from `doublon` where `id` not in
    ( Select id
         From `doublon` 
         group  by etablissement_id,amenities_id
         having Count(etablissement_id) > 1  and Count(amenities_id) > 1
         union
      Select id
         From `doublon` 
         group  by etablissement_id,amenities_id
         having Count(etablissement_id) = 1  and Count(amenities_id) = 1
     )
 )

我的表'doublon'的结构如下:

id
etablissement_id
amenities_id

结构表是这样的:

http://hpics.li/bbb5eda

我有2百万行,查询是慢,很多小时.. 有人知道如何优化这个查询以更快地执行它吗?

SqlFiddle

2 个答案:

答案 0 :(得分:1)

首先,您的查询不正确。但是继续阅读,可能在答案结束时我发现了你需要这么奇怪的查询的原因。

让我们讨论最后一个子查询:

Select id
From `doublon` 
group  by etablissement_id,amenities_id
having Count(etablissement_id) = 1  and Count(amenities_id) = 1

只有在至少发生以下其中一项情况时,才能使用SELECT查询GROUP BY子句中的列:

  • 它也存在于GROUP BY条款中;
  • 它用作aggregate function;
  • 的参数
  • 该列的值在功能上取决于GROUP BY子句中存在的列的值;例如,如果存在具有UNIQUE索引的列(或表的UNIQUE索引中存在的所有列)。

id不适合 1 以上的任何情况。这使得查询illegal符合SQL规范。

然而,

MySQL接受它并努力为其生成结果集,但它在documentation中说:

  

...服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的,这可能不是您想要的。

HAVING子句包含Count(etablissement_id)Count(amenities_id)。当etablissement_idamenities_id都不是 - NULL时,这两个表达式具有相同的值,并且与COUNT(*)(组中的行数)相同。它总是大于0(一个组不能包含0行)。

对于etablissement_idamenities_idNULL时生成的组,相应的COUNT()会返回0。当两者同时为NULL时,这也适用。

使用此信息,此查询将返回id行,其组合(etablissement_idamenities_id)在表中是唯一的(这些组只包含一行)和两个字段不是NULL

另一个GROUP BY查询(使用此UNION编辑)会从其组合(etablissement_id,{amenities_id,{}中返回不确定值 {1}})在表中不是唯一的(并且两个字段都不是NULL),如文档中引用的片段中所述。

似乎UNIONidetablissement_id的每一组(amenities_idetablissement_id)中挑选一个(随机)amenities_id不是 - NULL。外部SELECT打算忽略id选择的UNION,并提供给DELETE其他人。

(我认为甚至不需要中间SELECT,您可以在WHERE查询中使用其DELETE子句

我可以想象您需要运行此查询的唯一原因是表doubloncorrespondence tablemany-to-many relationship,它是在没有UNIQUE索引的情况下创建的({3}} etablissement_idamenities_id)(从相关表格导入的FOREIGN KEY列)。

如果这是您的意图,那么有更简单的方法可以实现这一目标。

我会创建doublon表的副本,使用正确的结构,然后我会使用DISTINCT查询# Create the new table CREATE TABLE `doublon_fixed` LIKE `doublon`; # Add the needed UNIQUE INDEX ALTER TABLE `doublon_fixed` ADD UNIQUE INDEX `etablissement_amenities`(`etablissement_id`, `amenities_id`); # Copy the needed values INSERT INTO `doublon_fixed` (`etablissement_id`, `amenities_id`) SELECT DISTINCT `etablissement_id`, `amenities_id` FROM `doublon`; # Swap the tables RENAME TABLE `doublon` TO `doublon_old`, `doublon_fixed` TO `doublon`; # Remove the old table DROP TABLE `doublon_old`; 来从旧表中获取所需的值。然后我会交换表并删除旧表。

查询:

RENAME

id查询从左到右以原子方式操作重命名。避免停机很有用。


备注:

1 如果etablissement_id列在功能上依赖于(amenities_idUNION)对,那么SELECT生成的所有组-ed查询包含单行。第一个SELECT不会产生任何结果,第二个{{1}}将返回整个表格。

答案 1 :(得分:0)

如果没有错,这应该有效

DELETE FROM doublon
WHERE  id IN (SELECT id
              FROM   doublon
              WHERE  id NOT IN (SELECT id
                                FROM   doublon
                                GROUP  BY etablissement_id,
                                          amenities_id
                                HAVING Count(etablissement_id) >= 1
                                       AND Count(amenities_id) >= 1))