用于优化的 MySQL 哈希索引

标签 mysql hash indexing b-tree

所以也许这不是菜鸟,但我正在弄乱几张 table 。

我有表 A 大约 45,000 条记录

我有表 B 大约 150 万条记录

我有一个问题:

update
    schema1.tablea a
    inner join (
        SELECT DISTINCT
            ID, Lookup,
            IDpart1, IDpart2
        FROM
            schema1.tableb
        WHERE
            IDpart1 is not NULL
        AND
            Lookup is not NULL
        ORDER BY
            ID,Lookup
    ) b Using(ID,Lookup)
set 
    a.Elg_IDpart1 = b.IDpart1, 
    a.Elg_IDpart2 = b.IDpart2
where
    a.ID is NOT NULL
AND
    a.Elg_IDpart1 is NULL

所以我在 ID 上强制索引,Lookup。每个表在这些列上也有一个索引,但由于子查询,我强制使用了它。

它需要永远运行,而且它真的应该需要,我想不到 5 分钟......

我的问题是关于索引,而不是查询。

我知道你不能在有序索引中使用散列索引。

我目前在 ID、Lookup sperately 和作为一个索引上都有索引,它是一个 B-Tree 索引。根据我的 WHERE 子句,哈希索引是否适合作为优化技术??

我可以有一个单一的哈希索引,其余的索引都是 B 树索引吗?

这不是主键字段。

我会发布我的解释,但我更改了这些表的名称。基本上它只为 ID 使用索引...而不是使用 ID,Lookup,我想强制它同时使用两者,或者至少将它变成另一种索引,看看是否有帮助?

现在我知道 MySQL 足够聪明,可以确定最合适的索引,那么它在做什么? Lookup 字段映射 ID 的第一部分和第二部分...

在此方面提供任何帮助或见解,我们将不胜感激。


更新

在我取出子查询后,UPDATE 上的 EXPLAIN

+----+-------------+-------+------+-----------------------------+--------------+---------+-------------------+-------+-------------+
| id | select_type | table | type |        possible_keys        |     key      | key_len |        ref        | rows  |    Extra    |
+----+-------------+-------+------+-----------------------------+--------------+---------+-------------------+-------+-------------+
|  1 | SIMPLE      | m     | ALL  | Lookup_Idx,ID_Idx,ID_Lookup |              |         |                   | 44023 | Using where |
|  1 | SIMPLE      | c     | ref  | ID_LookupIdx                | ID_LookupIdx |       5 | schema1.tableb.ID |     4 | Using where |
+----+-------------+-------+------+-----------------------------+--------------+---------+-------------------+-------+-------------+

tablea相关索引:

  • ID_LookupIdx(ID,查找)

tableb相关索引:

  • 身份证(ID)
  • Lookup_Idx(查找)
  • ID_Lookup_Idx(ID,查找)

所有的索引都是普通的 B 树。

最佳答案

首先针对您提出的具体问题进行处理:

  1. I currently have indexes on both ID, Lookup sperately, and as one index, and it is a B-Tree index. Based on my WHERE Clause, does a hash index fit for as an optimization technique??

    根据 CREATE INDEX Syntax 记录:

    +----------------+--------------------------------+
    | Storage Engine |    Permissible Index Types     |
    +----------------+--------------------------------+
    | MyISAM         | BTREE                          |
    | InnoDB         | BTREE                          |
    | MEMORY/HEAP    | HASH, BTREE                    |
    | NDB            | BTREE, HASH (see note in text) |
    +----------------+--------------------------------+
    

    因此,在考虑HASH 索引之前,应该意识到它MEMORYNDB< 中可用 存储引擎:所以你甚至可能不是一个选择。

    此外,请注意单独使用 IDLookup 组合的索引可能不是最佳的,因为您的 WHERE 谓词也会过滤 tablea.Elg_IDpart1tableb.IDpart1 - 您也可以从这些列的索引中受益。

  2. Can I have a single hash index, and the rest of the indexes b B-tree index?

    只要存储引擎支持所需的索引类型,您可以根据需要混合使用它们。

  3. instead of using the ID, Lookup, I would like to force it to use both, or at least turn it into a different kind of index and see if that helps?

    你可以使用 index hint强制 MySQL 使用与优化器原本选择的索引不同的索引。

  4. Now I know MySQL is smart enough to determine which index is most appropriate, so is that what it's doing?

    通常足够聪明,但并非总是如此。然而,在这种情况下,它可能已经确定索引的基数使得最好使用它选择的索引。


现在,根据您使用的 MySQL 版本,从子查询派生的表可能没有任何可用于进一步处理的索引:因此与 b 的连接可能需要一个对该派生表进行全面扫描(您的问题中没有足够的信息来确定这可能到底有多大问题,但是 schema1.tableb 有 150 万条记录表明它可能是一个重要因素)。

参见 Subquery Optimization获取更多信息。

因此,应尽可能避免使用派生表。在这种情况下,您的派生表似乎没有任何用途,因为可以直接连接 schema1.tableaschema1.tableb:

UPDATE   schema1.tablea a
    JOIN schema1.tableb b USING (ID, Lookup)
SET      a.Elg_IDpart1 = b.IDpart1, 
         a.Elg_IDpart2 = b.IDpart2
WHERE    a.Elg_IDpart1 IS     NULL
     AND a.ID          IS NOT NULL
     AND b.IDpart1     IS NOT NULL
     AND b.Lookup      IS NOT NULL
ORDER BY ID, Lookup

唯一丢失的是 DISTINCT 记录的过滤器,但是重复的记录将简单地(尝试)再次用相同的值覆盖更新的值——这不会有任何效果,但可能已证明成本非常高(尤其是该表中有这么多记录)。

在派生表中使用 ORDER BY 是没有意义的,因为不能依赖它来实现 UPDATE 的任何特定顺序,而在这个修订版本中它将确保任何覆盖先前更新的更新都按指定顺序进行:但有必要吗?也许它可以被删除并保存在任何排序操作中。

应该检查 WHERE 子句中的谓词:它们是否都是必需的(NOT NULL 检查 a.IDb.Lookup 是多余的,因为任何此类 NULL 记录都将被 JOIN 谓词消除)?

总而言之,这给我们留下了:

UPDATE   schema1.tablea a
    JOIN schema1.tableb b USING (ID, Lookup)
SET      a.Elg_IDpart1 = b.IDpart1, 
         a.Elg_IDpart2 = b.IDpart2
WHERE    a.Elg_IDpart1 IS     NULL
     AND b.IDpart1     IS NOT NULL

只有当性能仍然不能令人满意时,才应该进一步查看索引。相关列(即 JOINWHERE 谓词中使用的列)是否已编入索引?索引是否被选择供 MySQL 使用(请记住,每个表只能使用 一个 索引进行查找:用于测试 JOIN 谓词和过滤谓词:也许你需要一个合适的综合指数)?使用 EXPLAIN 检查查询执行计划以进一步调查此类问题。

关于用于优化的 MySQL 哈希索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21049449/

相关文章:

c# - 散列和加盐密码字段

indexing - 路由elasticsearch文档索引问题

基于 Python tile 的 numpy 数组处理

c# - 从数据库中获取时间戳字段的值并存储在字符串中

mysql - JOINS SQL(MYSQL)中的OR操作

ruby - 用Ruby中的哈希值总结对象区域

c++ - 为什么我们需要在 std::hash<sometype>()(somevalue) 中添加 ()?

mysql - 用于索引表的 OR 和 IN 运算符的替代方案

php - 试图从一种形式发布到两个数据库表 - Laravel 8

php - 从数据库查询结果