Mysql 优化查询和子查询
目前我有:Mysql 优化查询和子查询,mysql,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_p
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
)
);
我有两列(called和calling phone),其中我必须检查每个号码的所有发生率,并将计数(*)>4000的所有号码存储在另一个表中,将两列中的发生率相加。这个查询的问题是我做了2次子查询,子查询本身扫描了2次MyTable。我想把子查询存储在一个临时表中,然后扫描它。这是最好的方法吗?你有什么建议
编辑:我使用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毫秒
- 第二次进近需要800毫秒到1.8秒
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毫秒
- 第二次进近需要800毫秒到1.8秒
- 最后一次进近需要315到335毫秒
- 您可以将。。。在递归语句中经常使用的策略
(请原谅我的错误意图或支架)
尝试:
或者更快的可能是:
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;
正如您似乎理解的那样,插入到我将重写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)
MySQL不支持这种语法,至少可能不是OP使用的版本。是的,事实上我有一个错误。编辑主要帖子是因为我忘了指定我的引擎和mysqlversion@TimBiegeleisen真正地什么东西不适合它?您只能在“with…”表上使用select吗?请尝试在MySQL上运行您的查询。在发布代码之前是否对其进行了测试?with不是MySQL 5.7的有效语法。我想它是在MySQL 8.0中添加的,我不明白。你只是打断了我的提问。我需要记下所有的电话号码。这就是为什么我有一个OR,这就是我的问题所在,很抱歉我犯了错误——我编辑了我的答案,现在可能更好了。这不起作用。我的子查询是正确的,而您返回的结果是空的。我感谢您的努力,现在它正在工作,但是您的查询比我的慢2-3倍。我在一个非常小的数据库中测试它(myTable中约14k条记录)看看这个,当我结合两个内部连接时,从你的答案我得到一个空表,我认为这是因为(但我可能错了)你永远不会找到两个连接之间的交集。数字每次只能出现在一列中,不能同时出现在两列中。我需要做的是将所有出现次数超过4000次的数字(这个数字目前并不重要)和两列中的所有出现次数相加。这是可行的,但我最初的查询似乎仍然是最快的方法。你的查询大约需要520毫秒,而我的查询需要370毫秒。我想我做得比我已经做的要好得多。我发现,如果你删除distinct,效果会更好。我将您的答案标记为已接受的答案,但您应该修改itA“或”中的一个连接是相当昂贵的,这就是为什么我对我的答案不满意,但我不知道我们可以做什么。我不确定你是否应该接受我的答案。你的测试有什么消息吗?不幸的是,我对mu测试数据有一些问题。我需要在更大的桌子上测试它们。但我需要先完成其他事情
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;
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)