MySQL: index json arrays of variable length?

后端 未结 3 1049
轻奢々
轻奢々 2021-02-04 06:58

I want to make a tags column of type json:

e.g.,

id  |  tags
=========================================
1   |  \'["tag1"         


        
3条回答
  •  夕颜
    夕颜 (楼主)
    2021-02-04 07:52

    It's not practical to index an array in JSON in MySQL.

    You can use generated columns to extract each element of the array into a separate scalar column, and index each generated column. But how many of these columns will you need? How will you know which column contains the value you're searching for?

    You can use a generated column as @bostaf's answer shows, extracting multiple array values and making a comma-separated string. You can't use an plain index to search this string for a word that may occur in the middle. Perhaps you could use a fulltext index, but this only works if the array elements are each a single word.

    In April 2018, I gave a presentation about this kind of weakness using JSON in MySQL: How to Use JSON in MySQL Wrong.

    The better solution for multi-valued attributes is to store them in a dependent table, in the manner proscribed by database normalization. Then the values appear over multiple rows, in a single column, which you can index in a more straightforward way.


    Re your comment:

    I came up with a solution for enforcing uniqueness on a JSON array, but it depends on the elements of the array staying in sorted order.

    mysql> create table mytags ( tags json );
    mysql> insert into mytags values ('["tag1", "tag3", "tag5", "tag7"]');
    

    The JSON_UNQUOTE() function returns the JSON as a string.

    mysql> select json_unquote(tags) from mytags;
    +----------------------------------+
    | json_unquote(tags)               |
    +----------------------------------+
    | ["tag1", "tag3", "tag5", "tag7"] |
    +----------------------------------+
    

    Now we know how to make a generated column based on that, and then a UNIQUE KEY index on the generated column. This works in MySQL 5.7 and later.

    mysql> alter table mytags 
      add column j varchar(768) as (json_unquote(tags)), 
      add unique index (j);
    

    Now trying to insert the same array of values in the JSON column fails:

    mysql> insert into mytags (tags) values ('["tag1", "tag3", "tag5", "tag7"]');
    ERROR 1062 (23000): Duplicate entry '["tag1", "tag3", "tag5", "tag7"]' for key 'j'
    

    Unfortunately, there's no good way to ensure that the JSON array is sorted. See Sorted json array field So it's up to you to design your application code so that it always pre-sorts the values in the JSON array before inserting or updating.

提交回复
热议问题