【问题标题】:MySQL: nested select speed problemMySQL:嵌套选择速度问题
【发布时间】:2011-06-08 05:36:34
【问题描述】:

我有以下表格:

|ELEMENTS|
------------
|id_element|
|id_catalog|
|value|


|CATALOG|
------------
|id_catalog|
|catalog_name|
|show|
|status|

我尝试添加不同的缺陷(几种变体):

1) ELEMENT: pair(id_element, id_catalog) and id_element and id_catalog
2) ELEMENT: pair(id_element, id_catalog) and id_element
3) ELEMENT: pair(id_element, id_catalog) and id_catalog
4) ELEMENT: id_element and id_catalog

1) CATALOG: pair(show, status) and id_catalog
2) CATALOG: id_catalog and show and status

执行跟随选择:

SELECT DISTINCT `id_element` FROM `ELEMENTS`
       WHERE (id_catalog IN (SELECT `id_catalog` FROM `CATALOG` WHERE status=1 AND show = 1)) limit 10

如果有一些行,那么它的工作速度非常快。但如果它是空的 - 它需要超过 4 秒。

同时“SELECTid_catalogFROMCATALOGWHERE status=1 AND show = 1”在有一些行和空的情况下都能快速工作。

在表 ELEMENTS 中有 100.000 条记录 在表 CATALOG 中有 15.000 条记录

我也尝试过“加入”,但它比以前花费了更多时间。

为什么空查询工作这么长时间,我应该怎么做才能提高速度?

这里是解释答案:

id | select_type          | table                  | type              | possible_keys             | key        | key_len | ref    | rows   | Extra
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1  | 'PRIMARY',           |'ELEMENTS'              | 'index'           | ''                        | null       | null    | null   | 270044 | 'Using where; Using temporary'
2  | 'DEPENDENT SUBQUERY' | 'CATALOG'              | 'unique_subquery' | 'PRIMARY,pair,id_catalog' | 'PRIMARY'  | '4'     | 'func' | 1      | 'Using where'

【问题讨论】:

    标签: mysql database select join


    【解决方案1】:

    我想索引CATALOG(status,show) 可以快速回答子选择。

    然后一些关于 ELEMENTS(id_catalog) 的索引将加快对主要问题的回答。

    也许这取决于这些列的统计信息:如果它们没有足够的选择性,你最终会得到很多行。

    在使用上述两个索引时,能否显示EXPLAIN 的输出?

    【讨论】:

    • 谢谢,我在上面的问题中添加了答案。
    【解决方案2】:

    为什么不简单地编写一个连接来帮助优化器完成它的工作?

    SELECT DISTINCT id_element
    FROM elements JOIN catalog ON elements.id_catalog=catalog.id_catalog
    WHERE status=1 AND show = 1
    LIMIT 10
    

    (未经测试)

    【讨论】:

      【解决方案3】:

      嗯,您遇到问题的原因是您要为每个请求提取整个目录数据库并查找元素和目录之间的每个匹配项。如果 MySQL 找到 10 个条目,它就会退出,但如果它从未找到它们,它将继续检查您的整个数据库。我会使用EXISTS 查询来尝试提高性能。

      SELECT DISTINCT(e.id_element)
      FROM ELEMENTS e
      WHERE EXISTS (
          SELECT *
          FROM CATALOG c
          WHERE c.id_catalog = e.id_catalog
          AND c.status = 1
          AND c.show = 1)
      LIMIT 10;
      

      这将减少 MySQL 通过对内部查询强加 LIMIT 1 来为每个元素查找目录所花费的时间,但是当可能没有匹配项时,您总是冒着搜索时间过长的风险。

      【讨论】:

        【解决方案4】:

        我会把这些索引放在那里:

        CREATE INDEX idx_element_1 ON ELEMENT (id_catalog);
        CREATE INDEX idx_catalog_1 ON CATALOG (status, show);
        

        还有这些,尽管您的查询可能不需要它们(这些应该是主键,除非您有重复项):

        CREATE INDEX idx_element_2 ON ELEMENT (id_element);
        CREATE INDEX idx_catalog_2 ON CATALOG (id_catalog);
        

        您能否删除其他索引并创建这些索引并查看查询结果?

        【讨论】:

        • 在这种情况下,即使有一些行,它的工作时间也比以前长:(顺便说一下,ELEMENT 不使用任何索引。
        • @Anthony 什么意思,ELEMENT 不使用任何索引?如果您在 ELEMENT.id_catalog 上有一个索引,它应该使用它,因为它是 WHERE 子句的一部分。
        • 它是空的。我稍后会再试一次。只是想试试凯尔写的。
        【解决方案5】:

        谢谢大家。我通过表非规范化解决了它。因为这个dables中有太多的数据是分开的。 我决定把它合并到一张桌子上。现在它完美无缺。现在查询总是需要 0.03 秒。

        【讨论】:

        • 因此,您通过反规范化修复了一个查询,并破坏了其他受益于规范化的查询进程。这是一个糟糕的交易。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-14
        • 2011-05-16
        • 2019-01-06
        • 2021-12-13
        • 2019-02-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多