代码之家  ›  专栏  ›  技术社区  ›  Mikhail

在具有联合的视图中级联WHERE子句

  •  3
  • Mikhail  · 技术社区  · 14 年前

    这还没有解决,但我发现了原因: MySQL View containing UNION does not optimize well...In other words SLOW!


    原岗位:

    我正在为一个游戏开发数据库。有两张相同的桌子 equipment safety_dep_box . 为了检查玩家是否有设备,我想检查两张桌子。

    我不想做两个查询,而是想利用MySQL中的联合功能。我最近才知道我可以创建一个视图。我的观点是:

    CREATE VIEW vAllEquip AS SELECT * FROM equipment UNION SELECT * FROM safety_dep_box;
    

    视图创建得很好。但是当我跑步的时候

    SELECT * FROM vAllEquip WHERE owner=<id>
    

    查询永远都需要,而独立的选择查询很快。我想我知道原因,但我不知道如何解决。

    谢谢!

    附加信息:

    这两个表在结构上是相同的,但由于它们是1亿行表,所以被拆分了。 该结构包括int id上的主键和int owner上的多个索引。 我不明白的是以下两种情况之间的速度差:

    SELECT COUNT(*) FROM (SELECT * FROM equipment WHERE owner=1 UNION ALL SELECT * FROM safety_dep_box WHERE owner=1) AS uES;
    

    0.42秒

    SELECT COUNT(*) FROM (SELECT * FROM equipment WHERE owner=1 UNION  SELECT * FROM safety_dep_box WHERE owner=1) AS uES;
    

    0.37秒

    SELECT COUNT(*) FROM vAllEquip WHERE owner=1;
    

    60秒后中止


    版本:5.1.51

    mysql> explain SELECT * FROM equipment UNION SELECT * FROM safety_dep_box;
    +----+--------------+----------------+------+---------------+------+---------+------+---------+-------+
    | id | select_type  | table          | type | possible_keys | key  | key_len | ref  | rows    | Extra |
    +----+--------------+----------------+------+---------------+------+---------+------+---------+-------+
    |  1 | PRIMARY      | equipment      | ALL  | NULL          | NULL | NULL    | NULL | 1499148 |       |
    |  2 | UNION        | safety_dep_box | ALL  | NULL          | NULL | NULL    | NULL |  867321 |       |
    | NULL | UNION RESULT | <union1,2>     | ALL  | NULL          | NULL | NULL    | NULL |    NULL |       |
    +----+--------------+----------------+------+---------------+------+---------+------+---------+-------+
    

    带有WHERE子句

    mysql> explain SELECT * FROM equipment WHERE owner=1 UNION ALL SELECT * FROM safety_dep_box WHERE owner=1
        -> ;
    +----+--------------+----------------+------+-----------------------+-------+---------+-------+------+-------+
    | id | select_type  | table          | type | possible_keys         | key   | key_len | ref   | rows | Extra |
    +----+--------------+----------------+------+-----------------------+-------+---------+-------+------+-------+
    |  1 | PRIMARY      | equipment      | ref  | owner,owner_2,owner_3 | owner | 4       | const |    1 |       |
    |  2 | UNION        | safety_dep_box | ref  | owner,owner_3         | owner | 4       | const |    1 |       |
    | NULL | UNION RESULT | <union1,2>     | ALL  | NULL                  | NULL  | NULL    | NULL  | NULL |       |
    +----+--------------+----------------+------+-----------------------+-------+---------+-------+------+-------+
    
    2 回复  |  直到 14 年前
        1
  •  2
  •   Larry Lustig    14 年前

    首先,您应该使用union all而不是plain union。使用普通联合,引擎将尝试消除结果集的重复。这可能是你问题的根源。

    其次,在两个表中都需要所有者的索引,而不仅仅是一个。理想情况下,它们将是整型列。

    第三,Randolph是对的,您不应该在select语句中使用“*”。列出所有要包含的列。这在联合中尤其重要,因为列必须完全匹配,如果两个表中的列顺序不一致,则可能会强制进行某种类型转换,这会花费您一些时间。

    最后,短语“有两个相同的表”几乎总是提示您的数据库没有进行优化设计。这些可能是一张桌子。为了表明物品的所有权,您的安全箱表应该只包含物品的所有者ID和项目ID(与设备和玩家相关),并且可能包含一个额外的自动编号的整数键列。

        2
  •  0
  •   user114600    14 年前

    首先,不要在视图中使用select*。这是懒惰的代码。其次,在不知道基表是什么样子的情况下,我们更不可能帮助您。

    它之所以需要永远,是因为它必须构建完整的结果,然后对其进行过滤。您需要索引 owner 田地,不管它们是什么。