在 VIEW 中使用 JSON_ARRAYAGG 和 GROUP BY 避免 MySQL 全表扫描

Nat*_*ehr 5 mysql group-by view

我有两个表practice,并且facility具有通过链接表建立的一对多关系facility_practice

我想要一个将关系的“许多”部分聚合到 json 数组中的结果。以下查询产生所需的结果:

询问

select 
    practice.id
    , practice.name
    , practice.code

    , json_arrayagg(json_object(
        "id", facility.id
        , "name", facility.name
        , "code", facility.code
    )) as facility_json
from practice
left join facility_practice
    on facility_practice.practice_id = practice.id
left join facility
    on facility.id = facility_practice.facility_id
where practice.id = 1
group by practice.id;
Run Code Online (Sandbox Code Playgroud)

结果

+----+------+-------+---------------------------------------------------------------------------------------------+
| id | name |  code | facility_json                                                                               |
+----+------+-------+---------------------------------------------------------------------------------------------+
| 1  | Test |  NA   | [{"id": 1, "code": "NA", "name": "Test"}, {"id": 15, "code": "HV", "name": "Harbour View"}] |
+----+------+-------+---------------------------------------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

如果我执行explain上述查询,我​​会得到我所期望的结果:

解释

+----+-------------+-------------------+--------+-------------+
| id | select_type | table             | type   | key         |
+----+-------------+-------------------+--------+-------------+
| 1  | SIMPLE      | practice          | const  | PRIMARY     |
+----+-------------+-------------------+--------+-------------+
| 1  | SIMPLE      | facility_practice | ref    | practice_id |
+----+-------------+-------------------+--------+-------------+
| 1  | SIMPLE      | facility          | eq_ref | PRIMARY     |
+----+-------------+-------------------+--------+-------------+
Run Code Online (Sandbox Code Playgroud)

如果我随后尝试从该查询创建视图,MySQL 会突然对练习表执行全表扫描。我注意到,如果删除group by查询的一部分,它就不再进行全表扫描;然而,结果不再正确(显然)。

看法

drop view if exists practice_facility_v;    

create view practice_facility_v as
select 
    practice.id
    , practice.name
    , practice.code

    , json_arrayagg(json_object(
        "id", facility.id
        , "name", facility.name
        , "code", facility.code
    )) as facility_json
from practice
left join facility_practice
    on facility_practice.practice_id = practice.id
left join facility
    on facility.id = facility_practice.facility_id
group by practice.id;

select * from practice_facility_v where id = 1;
Run Code Online (Sandbox Code Playgroud)

解释

+----+-------------+-------------------+------------+--------+---------------+-------------+---------+-------------------------------------------+------+----------+----------------+
| id | select_type | table             | partitions | type   | possible_keys | key         | key_len | ref                                       | rows | filtered | Extra          |
+----+-------------+-------------------+------------+--------+---------------+-------------+---------+-------------------------------------------+------+----------+----------------+
| 1  | PRIMARY     | <derived2>        | (NULL)     | ref    | <auto_key0>   | <auto_key0> | 4       | const                                     | 1    | 100.00   |                |
+----+-------------+-------------------+------------+--------+---------------+-------------+---------+-------------------------------------------+------+----------+----------------+
| 2  | DERIVED     | practice          | (NULL)     | ALL    | PRIMARY       | (NULL)      | (NULL)  | (NULL)                                    | 7    | 100.00   | Using filesort |
+----+-------------+-------------------+------------+--------+---------------+-------------+---------+-------------------------------------------+------+----------+----------------+
| 2  | DERIVED     | facility_practice | (NULL)     | ref    | practice_id   | practice_id | 4       | ChargeBook.practice.id                    | 2    | 100.00   |                |
+----+-------------+-------------------+------------+--------+---------------+-------------+---------+-------------------------------------------+------+----------+----------------+
| 2  | DERIVED     | facility          | (NULL)     | eq_ref | PRIMARY       | PRIMARY     | 4       | ChargeBook.facility_practice.facility_id  | 1    | 100.00   |                |
+----+-------------+-------------------+------------+--------+---------------+-------------+---------+-------------------------------------------+------+----------+----------------+
Run Code Online (Sandbox Code Playgroud)