我有一个包含三个表的数据库,我需要将第一个表与另外两个表交叉引用,以创建第四个合并信息表。所有表都有一个常见的字段,这是MSISDN(移动/手机号码),长度至少为10位。
表1 - 819,248行
表2 - 75,308,813行
表3 - 17,701,196行
我想返回表1中的所有行,并在有匹配的MSISDN时附加表2和表3中的一些字段。 我的查询已经运行了超过24小时,我无法知道这样的事情需要多长时间。
这种类型的查询可能是一个常规项目 - 有没有办法显着缩短查询时间?
我已使用MSISDN索引表2和3以及我需要返回的字段。
我的查询是这样的:
create TABLE FinishedData
select
Table1.ADDRESS, table1.POSTAL, table1.MOBILE,
table1.FIRST, table1.LAST, table1.MID, table1.CARRIER,
table1.TOWN, table1.ID, table2.status as 'status1',
table2.CurrentNetworkName as 'currentnetwork1',
table2.DateChecked as 'datechecked1', table3.Status as 'status2',
table3.CurrentNetworkName 'currentnetwork2',
table3.DateChecked as 'datechecked2'
from
table1 left join (table2, table3)
on (right(table1.MOBILE, 10) = right(table2.MSISDN, 10)
AND right(table1.MOBILE,10) = right(table3.MSISDN,10))
MySQL运行在64位Windows机器上,内存为12GB,内存为8个逻辑内核@ 3GHz。 MySQLd在运行查询时仅使用10%的cpu和600MB的资源。
感谢任何帮助。
答案 0 :(得分:3)
kill性能问题与正确的功能使用此功能时,MySQL无法使用索引。
我的建议是:
通过这个小小的改变,MySQL可以使用索引来建立你的连接。
解释步骤:
1)创建新列:
Alter table table2 add column r_MSISDN varchar(200);
update table2 set r_MSISDN = reverse( MSISDN );
Alter table table3 add column r_MSISDN varchar(200);
update table3 set r_MSISDN = reverse( MSISDN );
2)新加入:
...
from
table1 left join (table2, table3)
on (right(table1.MOBILE, 10) = left(table2.r_MSISDN, 10)
AND right(table1.MOBILE,10) = left(table3.r_MSISDN,10))
答案 1 :(得分:1)
RIGHT
是一个功能。在where子句中使用函数意味着MySQL(可能还有任何数据库)不能使用索引,因为它必须在比较之前计算函数为每行返回的值。
如果您想更快地进行此查询,请考虑以规范化形式存储MSISDN并使用=
运算符进行比较。
现在我不确定MSISDN号码是什么样的。如果它是固定宽度的数字,那么您的工作很容易。如果它包含分隔符(空格/连字符)并且分隔符仅用于可读性,则应在存储到数据库之前删除它们。如果前10个字符很重要且剩余部分是可选的,您可以考虑将前10个字符和剩余字符存储在不同的列中。
答案 2 :(得分:1)
正如其他人已经提到的那样,问题在于right
函数不允许使用任何索引。
简单来说,对table1中每一行的当前查询会对table2进行全面扫描,并且对于每个匹配都会对table3进行完整扫描。考虑到table2和table3中有多少行,您很有可能在查询完成之前查看世界。
另一个问题是查询启动了一个巨大的事务,正如MySQL所认为的那样,它应该能够回滚,你可以考虑隔离级别。
我不会改变当前的表格。我将使用所需的列创建table2和table3的子类,并将右(table2.MSISDN,10)作为table2副本中的单独索引列添加(右(table3.MSISDN,10)在table3副本中)。
然后,您可以使用副本执行LEFT JOIN,或者甚至将副本缩减为与table1中的任何内容匹配的行,然后执行LEFT JOIN。