这是我在stackoverflow中的第一个问题,我很高兴成为这个社区的一员,因为它多次帮助了我。
我不是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 :(得分:1)
如您的查询计划所示,涉及五十万行的联接必然需要一些时间。 count(*)查询更快,因为它不需要读取tabla_maestra
表本身,但它仍然需要扫描索引cruce_empresa_apellido1
的所有行。
如果您将索引index_actividades_empresas
设为唯一索引(假设确实合适),或者您放弃该索引并创建列{{1>表empresa_apellido1
的主键。
如果即使这样也没有给你足够的性能,那么我唯一要做的就是给表tabla_actividades_empresas
一个整数类型的合成主键,并更改tabla_maestra的相应列以匹配。这应该有所帮助,因为将整数与整数进行比较比将字符串与字符串进行比较要快,即使您可以通过散列过滤掉(大多数)不匹配。
答案 1 :(得分:1)
我同意其他人(参见John Bollinger)关于缺少主键的问题。它非常喜欢ID(我注意到你担心它会被重复,但PK也会顺利地对待它 - 我的意思是MySQL的自动识别)。
为什么使用tabla_actividades_empresas
。empresa_apellido1
而不是查找要引用的tabla_maestra ID?
如果是这样,你可以为它定义外键:tabla_actividades_empresas
。maestra_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;
我还没有测试过。但从那时起它似乎是一个很好的行为。
哦......每次你需要更新所有数据行吗?除非,您只能更新被遗忘的人。您可以在UPDATE
之后INNER JOIN
之前应用LEFT 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 <> ''
不要忘记尝试调整关系。
答案 2 :(得分:0)
非常感谢您的回答。
事实上,表格 tabla_maestra 是一个包含企业信息的表格,但不包含“激活资料”字段的值(企业)。此外,' id '字段仍然是空的(我将在未来使用它。很难解释原因,但必须以这种方式完成)。
我需要添加每个企业加入一个辅助表' tabla_actividades_empresas '的活动,其中包含每个企业名称的活动。我只需要做一次,不再需要。然后,我可以删除“ tabla_actividades_empresas ”表格,因为我不需要它。
加入他们的唯一方法是“ empresa_apellido1 ”字段,也就是企业名称。
我已将“ tabla_actividades_empresas.empresa_apellido1 ”字段设为唯一,但它并未提高性能。
在“ tabla_actividades_empresas ”上定义外键是没有意义的,因为“ empresa_apellido1 ”字段仅对' tabla_actividades_empresas <是唯一的/ strong>',而不是' tabla_maestra '(在此表中,企业名称可以多次出现,因为企业可以在不同的地方拥有不同的办事处)。也就是说,' tabla_actividades_empresas '不包含重复的企业,但' tabla_maestra '重复了名称企业。
顺便说一下,“调整关系”是什么意思?我已经使用explain语句尝试了你的子查询,并且它没有正确使用索引,性能更差。