MySQL&;嵌套集:慢速联接(不使用索引)

MySQL&;嵌套集:慢速联接(不使用索引),mysql,sql,performance,indexing,nested-sets,Mysql,Sql,Performance,Indexing,Nested Sets,我有两张桌子: 地点: CREATE TABLE `localities` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `type` varchar(30) NOT NULL, `parent_id` int(11) DEFAULT NULL, `lft` int(11) DEFAULT NULL, `rgt` int(11) DEFAULT NULL, PRIMARY K

我有两张桌子:

地点:

CREATE TABLE `localities` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `type` varchar(30) NOT NULL,
  `parent_id` int(11) DEFAULT NULL,
  `lft` int(11) DEFAULT NULL,
  `rgt` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_localities_on_parent_id_and_type` (`parent_id`,`type`),
  KEY `index_localities_on_name` (`name`),
  KEY `index_localities_on_lft_and_rgt` (`lft`,`rgt`)
) ENGINE=InnoDB;
地点:

CREATE TABLE `locatings` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `localizable_id` int(11) DEFAULT NULL,
  `localizable_type` varchar(255) DEFAULT NULL,
  `locality_id` int(11) NOT NULL,
  `category` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_locatings_on_locality_id` (`locality_id`),
  KEY `localizable_and_category_index` (`localizable_type`,`localizable_id`,`category`),
  KEY `index_locatings_on_category` (`category`)
) ENGINE=InnoDB;
localities表作为嵌套集实现

现在,当用户属于某个位置(通过某个定位)时,他也属于其所有祖先(更高级别的位置)。我需要一个查询,将选择所有用户都属于一个视图的所有地方

以下是我的尝试:

select distinct lca.*, lt.localizable_type, lt.localizable_id 
from locatings lt
join localities lc on lc.id = lt.locality_id
left join localities lca on (lca.lft <= lc.lft and lca.rgt >= lc.rgt)
最后一个连接显然没有像我期望的那样使用lft、rgt索引。我绝望了

更新: 按照@cairnz的建议添加一个条件后,查询仍然需要太多的时间来处理

更新2:列名而不是星号

更新的查询:

SELECT DISTINCT lca.id, lt.`localizable_id`, lt.`localizable_type` 
FROM locatings lt FORCE INDEX(index_locatings_on_category)
JOIN localities lc
    ON lc.id = lt.locality_id
INNER JOIN localities lca
    ON lca.lft <= lc.lft AND lca.rgt >= lc.rgt
WHERE lt.`category` != "Unknown";

感谢您的帮助。

啊,我刚刚想到了这一点

由于您需要表中的所有内容,mysql决定使用完整表扫描,因为它认为这样更有效

为了获得一些关键用法,添加一些过滤器以限制对所有表中的每一行的查找

更新答案:

你的第二个问题没有意义。你是左连接到lca,但你有一个过滤器,这否定了左连接本身。此外,您在查询的最后一步中查找数据,这意味着您必须查看所有lt、lc和lca才能找到数据。此外,在位置上没有最左边列“type”的索引,因此仍然需要进行完整的表扫描以查找数据


如果您有一些示例数据和您正在尝试实现的示例,可能会更容易提供帮助。

尝试使用强制索引,也许这只是优化器的问题

看起来你想要的是单一结果的父母

根据在SQL中定义嵌套集的负责人Joe Celko所说,“此模型是显示零件爆炸的自然方式,因为最终装配是由分解为单独零件的物理嵌套装配组成的。”

换句话说,嵌套集用于在单个集合中有效地将子级过滤到任意数量的独立级别。您有两个表,但我看不出集合“locatings”的属性在哪里不能被反规范化为“localities”

如果localities表有一个geometry列,我能否从“定位”中找到一个位置,然后使用单个过滤器在一个表上选择:parent.lft=row.rgt

更新

在这个答案中,有一个例子,下面的例子将所有祖先的深度任意设置为100000:

SELECT  hp.id, hp.parent, hp.lft, hp.rgt, hp.data
FROM    (
    SELECT  @r AS _id,
            @level := @level + 1 AS level,
            (
            SELECT  @r := NULLIF(parent, 0)
            FROM    t_hierarchy hn
            WHERE   id = _id
            )
    FROM    (
            SELECT  @r := 1000000,
                    @level := 0
            ) vars,
            t_hierarchy hc
    WHERE   @r IS NOT NULL
    ) hc
JOIN    t_hierarchy hp
ON      hp.id = hc._id
ORDER BY
    level DESC

您是否尝试过在同一索引中不使用lft和rft?(一个用于lft,一个用于rft)根据您的更新更新答案。谢谢,查询速度快得多,但仍然需要太多时间。我用新的查询和解释更新了我的问题。对不起,这可能是一个愚蠢的问题,但是你添加过滤器的意思是什么?你的查询必须处理lt表,连接lc,连接lca。您拥有的过滤器位于lca中,这是查询的最后一个“步骤”。然后,它可以扫描lca表中与类型匹配的行!=“未知”,但为了达到这一点,它已经阅读了lt和lc,如果这是有意义的。此外,您还有一个到该表的左连接,这意味着您可以在那里有空记录,但您正在WHERE子句中过滤它,删除所有空记录(相当于一个内部连接)。也许你们的意思是你们的过滤器在lc上,或者在lt上。若你们在lt表上过滤,那个么它在lc和lca中要扫描的行就更少了。你们的意思是这样的吗。。。其中lt.
类别
!=“未知”;我们在localities表中有大约12000条记录,在Locating中有大约4000条记录,查询需要半分钟的时间来处理。那不好,是吗?听起来更像。如果你现在在lt.category上有一个索引,它应该会加快搜索速度。这样,就更有可能在lc和lca表上使用以下索引。当您添加这样的过滤器和索引时,解释会说什么。请记住,您不能使用键
localizable\u和\u category\u index
localizable\u type
localizable\u id
category
)仅用于搜索类别,因为它不是索引中最左边的列。同样,将
DISTINCT
替换为
GROUP BY
@FrancisAvila将DISTINCT替换为GROUP BY没有任何区别。
+----+-------------+-------+--------+-----------------------------------------+-----------------------------+---------+---------------------------------+-------+----------+-------------------------------------------------+
| id | select_type | table | type   | possible_keys                           | key                         | key_len | ref                             | rows  | filtered | Extra                                           |
+----+-------------+-------+--------+-----------------------------------------+-----------------------------+---------+---------------------------------+-------+----------+-------------------------------------------------+
|  1 | SIMPLE      | lt    | range  | index_locatings_on_category             | index_locatings_on_category | 153     | NULL                            |  2545 |   100.00 | Using where; Using temporary                    |
|  1 | SIMPLE      | lc    | eq_ref | PRIMARY,index_localities_on_lft_and_rgt | PRIMARY                     | 4       | bzzik_production.lt.locality_id |     1 |   100.00 |                                                 |
|  1 | SIMPLE      | lca   | ALL    | index_localities_on_lft_and_rgt         | NULL                        | NULL    | NULL                            | 11570 |   100.00 | Range checked for each record (index map: 0x10) |
+----+-------------+-------+--------+-----------------------------------------+-----------------------------+---------+---------------------------------+-------+----------+-------------------------------------------------+
SELECT  hp.id, hp.parent, hp.lft, hp.rgt, hp.data
FROM    (
    SELECT  @r AS _id,
            @level := @level + 1 AS level,
            (
            SELECT  @r := NULLIF(parent, 0)
            FROM    t_hierarchy hn
            WHERE   id = _id
            )
    FROM    (
            SELECT  @r := 1000000,
                    @level := 0
            ) vars,
            t_hierarchy hc
    WHERE   @r IS NOT NULL
    ) hc
JOIN    t_hierarchy hp
ON      hp.id = hc._id
ORDER BY
    level DESC