2014-10-17 31 views
4

这是我在stackoverflow中的第一个问题,我很高兴成为这个社区的一员,因为它帮了我很多次。MySQL - 非常简单的加入时间太长

我不是SQL和MySQL的专家,但我正在一个需要大表(百万行)的项目中工作。 我在加入时遇到问题,我不明白为什么需要这么长时间。感谢提前:)

下面是表:

CREATE TABLE IF NOT EXISTS tabla_maestra(
id int UNIQUE, 
codigo_alta char(1), 
nombre varchar(100), 
empresa_apellido1 varchar(150), 
apellido2 varchar(50), 
tipo_via varchar(20), 
nombre_via varchar(100), 
numero_via varchar(50), 
codigo_via char(5), 
codigo_postal char(5), 
nombre_poblacion varchar(100), 
codigo_ine char(11), 
nombre_provincia varchar(50), 
telefono varchar(250) UNIQUE, 
actividad varchar(100), 
estado char(1), 
codigo_operadora char(3) 
); 

CREATE TABLE IF NOT EXISTS tabla_actividades_empresas(
empresa_apellido1 varchar(150), 
actividad varchar(100) 
); 

这里是我想要做的查询:

UPDATE tabla_maestra tm 
INNER JOIN tabla_actividades_empresas tae 
ON (tm.nombre!='' AND tae.empresa_apellido1=tm.empresa_apellido1) 
SET tm.actividad=tae.actividad; 

这个查询的时间太长,并执行它之前,我是想以测试需要多长时间才能进行此简单查询:

SELECT COUNT(*) FROM tabla_maestra tm 
INNER JOIN tabla_actividades_empresas tae 
ON (tm.nombre!='' AND tae.empresa_apellido1=tm.empresa_apellido1); 

它仍然需要太长时间,为什么。下面是我用的指标:

CREATE INDEX cruce_nombre 
USING HASH 
ON tabla_maestra (nombre); 

CREATE INDEX cruce_empresa_apellido1 
USING HASH 
ON tabla_maestra (empresa_apellido1); 

CREATE INDEX index_actividades_empresas 
USING HASH 
ON tabla_actividades_empresas(empresa_apellido1); 

如果我使用EXPLAIN语句,这些结果如下:

http://oi59.tinypic.com/2zedoy0.jpg

我会如此感激收到任何答案,可以帮助我。非常感谢,丹妮。

+0

主键的缺失可能会导致缓慢的perforanace。 – 2014-10-17 13:57:11

回答

1

包含五十万行的连接 - 如查询计划所示 - 必然需要一些时间。 count(*)查询更快,因为它不需要读取tabla_maestra表本身,但仍需要扫描索引cruce_empresa_apellido1的所有行。

它可以帮助一些,如果你做指数index_actividades_empresas一个唯一指数(假设这确实是合适的),或者相反,如果你丢弃的索引,将列empresa_apellido1tabla_actividades_empresas的主键。

如果即使这样也不能提供足够的性能,那么我唯一要做的其他事情就是给表tabla_actividades_empresas一个整数类型的合成主键,并将tabla_maestra的相应列更改为匹配。这应该有所帮助,因为将整数与整数进行比较比将字符串与字符串进行比较要快,即使可以通过散列过滤(大部分)不匹配。

1

我同意其他人的看法(参见John Bollinger)关于它缺少主键的问题。它的ID很高(我注意到你担心它会被重复,但是PK也能顺利处理它 - 我的意思是MySQL的AUTOINCREMENT)。

为什么使用tabla_actividades_empresasempresa_apellido1而不是查找要引用的tabla_maestra的ID?

如果是这样,你可以定义外键:tabla_actividades_empresasmaestra_id

因为如果您将表与非字符串类型相关联会更好。

您也可以在它们之间的JOIN操作之前子查询这些表。这是一个例子:

UPDATE (SELECT * FROM tabla_maestra WHERE nombre != '') AS tm 
INNER JOIN tabla_actividades_empresas AS tae 
ON tae.empresa_apellido1 = tm.empresa_apellido1 
SET tm.actividad = tae.actividad; 

我还没有测试过它。但从那以后,它似乎是一个很好的行为。

哦......每次你需要更新所有的数据行吗?除非,你只能更新被遗忘者。您可以在LEFT JOIN之后应用UPDATEINNER JOIN以确定需要更新的项目。它有意义吗?我不是任何专家,但考虑一下可能很有用。

编辑

您可能也测试一些子查询:

UPDATE tabla_maestra AS main, tabla_actividades_empresas AS aggr 
SET main.actividad = aggr.actividad 
WHERE main.empresa_apellido1 = aggr.empresa_apellido1 
AND main.nombre <> '' 

不要忘了尝试调整的关系。

0

非常感谢你的回答。

事实是,表“tabla_maestra”是包含关于企业信息的表格,但开不包含对“ACTIVIDAD”场(企业活动)的值。此外,'id'字段仍然是空的(我将来会这样做,很难解释原因,但必须这样做)。

我需要将每个企业的活动添加到包含每个企业名称的活动的辅助表'tabla_actividades_empresas'中。我只需要做一次,不要再做了。然后,我将能够删除表'tabla_actividades_empresas',因为我不需要它。

并且加入它们的唯一方法是通过字段'empresa_apellido1',这就是说,企业的名称。

我已将该字段设为'tabla_actividades_empresas.empresa_apellido1''唯一,但它不会提高性能。

而且它没有意义的定义上的“tabla_actividades_empresas”的外键,因为该领域“empresa_apellido1”只为“tabla_actividades_empresas独特的,而不是为“tabla_maestra”(在这张表中,企业名称可能会出现很多次,因为企业可能在不同的地方有不同的办公室)。也就是说'tabla_actividades_empresas'不包含重复企业,但'tabla_maestra'已重复名称企业。

顺便说一下,“调整关系”是什么意思?我已经用explain语句尝试过你的子查询,并且它没有正确使用索引,性能更差。