MySQL:嵌套选择速度问题

时间:2011-06-08 05:36:35

标签: mysql database select join

我跟随表:

|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秒。

与此同时,“SELECT id_catalog FROM CATALOG WHERE 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'

5 个答案:

答案 0 :(得分:2)

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

然后ELEMENTS(id_catalog)上的一些索引会加快主要问题的答案。

也许这取决于这些专栏的统计数据:它们没有足够的选择性,无论如何你最终都会有很多行。

使用上面的两个索引时,你能显示EXPLAIN的输出吗?

答案 1 :(得分:2)

为什么不简单地编写连接以帮助优化器完成其工作?

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

(未测试的)

答案 2 :(得分:1)

那么,您遇到问题的原因是您为每个请求提取整个目录数据库并查找元素和目录之间的每个匹配项。如果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;

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

答案 3 :(得分:1)

我会把这些指数放在那里:

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);

您是否可以删除其他索引并创建这些索引并使用查询结果进行检查?

答案 4 :(得分:-1)

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