优化查询和子查询

时间:2018-02-26 10:06:55

标签: mysql

目前我有这个:

insert into temp select  * from myTable where (called_phone in
(
    select number1 from
    (
        SELECT *  FROM
        (
            SELECT called_phone as number1, count(*) as conto
            FROM myTable
            GROUP BY called_phone

        ) AS subquery
        union 
        SELECT * FROM
        (
            SELECT calling_phone as number1, count(*) as conto
            FROM myTable
            GROUP BY calling_phone

        ) AS subquery1
    )as subquery3
    GROUP BY number1
    having sum(conto) > 4000
))
or
(calling_phone in 
    (
        select number1 from
        (
            SELECT *  FROM
            (
                SELECT called_phone as number1, count(*) as conto
                FROM myTable
                GROUP BY called_phone

            ) AS subquery
            union 
            SELECT * FROM
            (
                SELECT calling_phone as number1, count(*) as conto
                FROM myTable
                GROUP BY calling_phone

            ) AS subquery1
        )as subquery3
        GROUP BY number1
        having sum(conto) > 4000
    )
);

我有2列(称为和呼叫电话),其中我必须检查每个号码的所有存储,并存储在另一个表中,所有具有计数(*)>的数字4000总结两列中的出现。这个查询的问题在于我做了子查询的2倍,子查询本身扫描MyTable的2倍。我想将子查询存储在临时表中,然后扫描它。这是最好的方法吗?你会建议什么?

编辑:我使用MySQL 5.7和MyISAM作为引擎

EDIT2 :试过这个:

create table test (`number1` VARCHAR(255) not NULL, primary key (`number1`));

insert into test(number1) select number1 from 
    (
        SELECT *  FROM
        (
            SELECT called_phone as number1, count(*) as conto
            FROM myTable
            GROUP BY called_phone

        ) AS subquery
        union 
        SELECT * FROM
        (
            SELECT calling_phone as number1, count(*) as conto
            FROM myTable
            GROUP BY calling_phone

        ) AS subquery1
    )as subquery3
    GROUP BY number1
    having sum(conto) > 4000;



insert into temp select  * from myTable where (called_phone in
(
    select number1 from test
    ))
or
(calling_phone in 
    (
        select number1 from test
));

drop table test;

但这要慢得多(至少在我的测试数据上,这是一个约14条记录的表格)

  • 第一种方法需要350毫秒到380毫秒
  • 第二种方法需要800ms到1.8s

最终编辑:我正在编写产生最佳结果的查询,它来自@Daniel E的答案。

insert into temp
SELECT t1.* myTable t1 
INNER JOIN 
 (
   select number1 from
        (
            SELECT *  FROM
            (
                SELECT called_phone as number1, count(*) as conto
                FROM myTable
                GROUP BY called_phone

            ) AS subquery
            union 
            SELECT * FROM
            (
                SELECT calling_phone as number1, count(*) as conto
                FROM myTable
                GROUP BY calling_phone

            ) AS subquery1
        )as subquery3
        GROUP BY number1
        having sum(conto) > 4000
 ) t2 ON (t2.number1 = t1.called_phone
        OR 
         t2.number1 = t1.calling_phone)
  • 第一种方法需要350毫秒到380毫秒
  • 第二种方法需要800ms到1.8s
  • 最后一个方法需要315到335毫秒

3 个答案:

答案 0 :(得分:1)

你似乎明白了Insert Into I我只会重写select,而不是使用IN和OR,我使用1个内连接:

SELECT t1.* FROM myTable t1 
INNER JOIN 
 (
   select number1 from
        (
            SELECT *  FROM
            (
                SELECT called_phone as number1, count(*) as conto
                FROM myTable
                GROUP BY called_phone

            ) AS subquery
            union 
            SELECT * FROM
            (
                SELECT calling_phone as number1, count(*) as conto
                FROM myTable
                GROUP BY calling_phone

            ) AS subquery1
        )as subquery3
        GROUP BY number1
        having sum(conto) > 4000
 ) t2 ON (t2.number1 = t1.called_phone
        OR 
         t2.number1 = t1.calling_phone)

答案 1 :(得分:0)

您可以使用通常在递归语句中使用的WITH AS ...策略。

(请原谅我错误的意图或大括号)

       with numbersRelation as (
            select number1 from
            (
                SELECT *  FROM
                (
                    SELECT called_phone as number1, count(*) as conto
                    FROM myTable
                    GROUP BY called_phone

                ) AS subquery
                union 
                SELECT * FROM
                (
                    SELECT calling_phone as number1, count(*) as conto
                    FROM myTable
                    GROUP BY calling_phone

                ) AS subquery1
            ) as subquery3
            GROUP BY number1
            having sum(conto) > 4000
        )
        insert into temp select  * from myTable where (called_phone in numbersRelation or
        calling_phone in numbersRelation)

答案 2 :(得分:-1)

尝试:

insert into temp 
select  * from myTable where called_phone in (
    select number1 from (
        SELECT called_phone as number1
        FROM myTable
        union all
        SELECT calling_phone as number1
        FROM myTable ) subquery
    GROUP BY number1
    having count(number1) > 4000 )

union 

select  * from myTable where calling_phone in (
    select number1 from (
        SELECT called_phone as number1
        FROM myTable
        union all
        SELECT calling_phone as number1
        FROM myTable ) subquery
    GROUP BY number1
    having count(number1) > 4000 )

或者可能更快:

insert into tabletemp 
    select number1 from (
        SELECT called_phone as number1
        FROM myTable
        union all
        SELECT calling_phone as number1
        FROM myTable ) subquery
    GROUP BY number1
    having count(number1) > 4000 ) ;

insert into temp 
select  * 
from myTable as mt 
join tabletemp tbt on (mt.called_phone = tbt.number1 or mt.calling_phone = tbt.number1);

drop table tabletemp;