【问题标题】:Joining two tables MySQL is slow even with indexing即使有索引,连接两个表 MySQL 也很慢
【发布时间】:2016-02-24 19:22:45
【问题描述】:

我有两张桌子:

第一个 table1 是动态创建的(当用户从​​ Web 服务器提交数据时),通常约为 50K 行。第二个表是一个查找表table2,有大约 1000 万行。

我正在尝试将两个表加入四列,如下所示:

从表 1 中选择 t.id 加入表2 米 开(t.name = m.name AND t.pos = m.pos AND t.ref = m.ref AND t.alt = m.alt);

我已在 table2 中为 name (VARCHAR)、pos (INT)、ref (CHAR) 和 alt (CHAR) 列编制索引,但查询仍然需要很长时间才能完成.

关于这里可能出现什么问题的任何指针?

谢谢


EXPLAIN的输出:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 49329 100.00 使用 where 1 SIMPLE t2 NULL ref table2_name,table2_pos,table2_ref,table2_alt table2_name 32 my_db.t1.NAME 2488 0.00 使用索引条件;使用哪里

【问题讨论】:

  • 你为什么不用id的?
  • @by0,这些表的引擎是什么?
  • 因为我是根据用户在网络服务器上提交的内容加入的,如果这有意义的话。引擎是 InnoDB
  • 当我对慢速查询进行故障排除时,我首先看到的是“解释”的结果。你已经试过了吗? dev.mysql.com/doc/refman/5.7/en/explain.html
  • 您是制作了 4 个单独的索引,还是制作了一个复合索引?我认为这 4 个单一索引在这里没有帮助 - 如果我错了,请纠正我。

标签: mysql sql database join


【解决方案1】:

name, pos, ref, alt上创建复合索引

喜欢

INDEX theIndex (name,pos,ref, alt)

此外,4 个单一索引会有所帮助 - 请参阅 http://dev.mysql.com/doc/refman/5.7/en/index-merge-optimization.html - 但不如复合索引那么多。

【讨论】:

  • 以防提问者需要它,您可能需要包含创建索引的语法。
  • 谢谢!花了一整天的时间来解决这个问题!如果我不想按一两列查询,是否还需要创建单独的索引?还是复合索引就足够了?
  • 当然——如果您只想通过这些列的某些前缀进行查询——比如名称、名称 pos 或名称 pos ref,那么您不需要单独的索引。但是,例如,如果您需要 pos 本身,那么您将需要一个单独的索引。
【解决方案2】:

这里有两件事要尝试:

  1. 第一个是最简单的 - 更改连接子句的顺序以将 varchar 列移到末尾。

SELECT t.id FROM table1 t JOIN table2 m ON (t.pos = m.pos AND t.ref = m.ref AND t.alt = m.alt AND t.name = m.name);

  1. 这需要更多的工作,但添加一个新的计算列,它会根据 4 列生成一个数字散列。删除 pos、ref、alt 和 name 上的索引,并将新索引添加到哈希列。然后在您的连接子句中包含哈希列。

SELECT t.id FROM table1 t JOIN table2 m ON (t.hash = m.hash AND t.pos = m.pos AND t.ref = m.ref AND t.alt = m.alt AND t.name = m.name);

编辑:不查看您的数据库和查询执行计划,很难解决此问题,但我的猜测是 MySQL 很难加入 VARCHAR 列。你能用

的结果更新你的问题吗

EXPLAIN SELECT t.id FROM table1 t JOIN table2 m ON (t.name = m.name AND t.pos = m.pos AND t.ref = m.ref AND t.alt = m.alt)

【讨论】:

    【解决方案3】:

    任何表的索引:

    SELECT 
      CONCAT(
        'ALTER TABLE ', 
        TABLE_NAME, 
        ' ', 
        'ADD ', 
        IF(
          NON_UNIQUE = 1, 
          CASE UPPER(INDEX_TYPE) WHEN 'FULLTEXT' THEN 'FULLTEXT INDEX' WHEN 'SPATIAL' THEN 'SPATIAL INDEX' ELSE CONCAT(
            'INDEX ', INDEX_NAME, ' USING ', INDEX_TYPE
          ) END, 
          IF(
            UPPER(INDEX_NAME) = 'PRIMARY', 
            CONCAT(
              'PRIMARY KEY USING ', INDEX_TYPE
            ), 
            CONCAT(
              'UNIQUE INDEX ', INDEX_NAME, ' USING ', 
              INDEX_TYPE
            )
          )
        ), 
        '(', 
        GROUP_CONCAT(
          DISTINCT CONCAT('', COLUMN_NAME, '') 
          ORDER BY 
            SEQ_IN_INDEX ASC SEPARATOR ', '
        ), 
        ');'
      ) AS 'Show_Add_Indexes' 
    FROM 
      information_schema.STATISTICS 
    WHERE 
      TABLE_SCHEMA = 'your_database' 
      and TABLE_NAME = 'your_table';
    -- GROUP BY 
    --   TABLE_NAME, 
    --   INDEX_NAME 
    -- ORDER BY 
    --   TABLE_NAME ASC, 
    --   INDEX_NAME ASC;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-01
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多