【问题标题】:MySQL - Very simple Join is taking too longMySQL - 非常简单的加入耗时太长
【发布时间】:2014-12-13 02:48:35
【问题描述】:

这是我在 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

如果能收到任何可以帮助我的答案,我将不胜感激。非常感谢, 丹妮。

【问题讨论】:

  • 缺少主键可能会导致性能缓慢。

标签: mysql sql join indexing


【解决方案1】:

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

如果您将索引 index_actividades_empresas 设为 唯一 索引(假设这确实合适),或者您删除该索引并将列 empresa_apellido1 设为表 @ 的主键,这可能会有所帮助987654325@.

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

【讨论】:

    【解决方案2】:

    我同意其他人(参见 John Bollinger 即)关于缺少主键的观点。它非常适合 ID(我注意到您担心它会重复,但 PK 也很顺利地处理它 - 我的意思是 MySQL 的 AUTOINCREMENT)。

    您为什么使用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;
    

    我没有测试过。但从那时起,这似乎是一种很好的行为。

    哦...每次您都需要更新所有数据行吗?除非,您只能更新被遗忘的内容。您可以在LEFT JOIN 之后通过INNER JOIN 应用UPDATE,以确定需要更新的内容。它有道理吗?我不是任何专家,但考虑一下会很有用。

    编辑

    你也可以测试一些子查询:

    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 <> ''
    

    不要忘记尝试调整关系。

    【讨论】:

      【解决方案3】:

      非常感谢您的回答。

      事实上,表“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”包含重复名称企业。

      对了,“调整关系”是什么意思?我用解释语句尝试过你的子查询,它没有正确使用索引,性能更差。

      【讨论】:

        猜你喜欢
        • 2013-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-17
        相关资源
        最近更新 更多