Avoid MySQL full table scan with JSON_ARRAYAGG and GROUP BY in a VIEW

Viewed 533

I have two tables practice and facility that have a one to many relationship that is established with a linking table facility_practice.

I would like a result that aggregates the "many" portion of the relationship in a json array. The following query yields the desired result:

Query

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;

Result

+----+------+-------+---------------------------------------------------------------------------------------------+
| id | name |  code | facility_json                                                                               |
+----+------+-------+---------------------------------------------------------------------------------------------+
| 1  | Test |  NA   | [{"id": 1, "code": "NA", "name": "Test"}, {"id": 15, "code": "HV", "name": "Harbour View"}] |
+----+------+-------+---------------------------------------------------------------------------------------------+

If I explain the above query, I get about what I would expect:

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     |
+----+-------------+-------------------+--------+-------------+

If I then try and create a view out of that query MySQL suddenly performs a full table scan on the practice table. I have noticed that if I remove the group by portion of the query it no longer does a full table scan; however, the result is no longer correct (obviously).

View

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;

Explain

+----+-------------+-------------------+------------+--------+---------------+-------------+---------+-------------------------------------------+------+----------+----------------+
| 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   |                |
+----+-------------+-------------------+------------+--------+---------------+-------------+---------+-------------------------------------------+------+----------+----------------+
0 Answers
Related