Есть ли какой-либо способ избежать ЛЕВОГО ПРИСОЕДИНЕНИЯ к одной и той же таблице

#mysql

Вопрос:

Есть две таблицы, т. е. пользователь и атрибут.

таблица пользователей-

  -----------------------------------------------------------------------
|   user_id |   u_at1   |   u_at2   |   u_at3   |   u_at4   |   u_atN   |   
 -----------------------------------------------------------------------
|   1       |    3      |     4     |   6       |   100     |   Null    |   
 -----------------------------------------------------------------------
|   2       |    Null   |     623   |   Null    |   85      |    1      |   
 -----------------------------------------------------------------------
 

таблица атрибутов

 -----------------------
|   at_id   |   at_text |
 -----------------------
|    1      |    at1    |
 -----------------------
|    2      |    at2    |
 -----------------------
|    3      |    at3    |
 -----------------------
|    4      |    at4    |
 -----------------------
|    5      |    at5    |
 -----------------------
|    6      |    at6    |
 -----------------------
|    85     |    at85   |
 -----------------------
|    100    |    at100  |
 -----------------------
|    500    |    at500  |
 -----------------------
|    623    |    at623  |
 -----------------------
 

В таблице атрибутов хранятся идентификатор атрибута и текст атрибута. В таблице пользователей в столбце атрибутов пользователя (например, u_at3) хранится идентификатор атрибута. В таблице пользователей столбец u_atN является, например, целевым, т. е. количество столбцов атрибутов может быть u_at20. Вот почему я не включил сюда всю колонку.

Теперь мой вопрос: это нормально, если я сделаю ЛЕВОЕ СОЕДИНЕНИЕ 20 раз для одной и той же таблицы или есть какой-либо другой способ, которым я могу это сделать? Вот мой вопрос-

  SELECT 
    `user`.*,
    `attribute1`.`at_text`,
    `attribute2`.`at_text`
    `attribute3`.`at_text`
    `attribute4`.`at_text`
    .....................
    .....................
    `attribute20`.`at_text`
    
FROM `user`
LEFT JOIN `attribute` `attribute1` ON `user`.`u_at1` = `attribute1`.`at_id`,
LEFT JOIN `attribute` `attribute2` ON `user`.`u_at2` = `attribute2`.`at_id`,
LEFT JOIN `attribute` `attribute3` ON `user`.`u_at3` = `attribute3`.`at_id`,
LEFT JOIN `attribute` `attribute4` ON `user`.`u_at4` = `attribute4`.`at_id`,
...................................................................
...................................................................
JOIN `attribute` `attribute20` ON `user`.`u_at20` = `attribute20`.`at_id`,
WHERE `user_id` = 2;
 

Комментарии:

1. Нормализуйте свою схему

Ответ №1:

При использовании агрегации MySQL вы можете использовать функцию агрегации MAX() для строк, чтобы выполнить полное объединение и использовать оператор if для использования значения атрибута или null для каждого поля в зависимости от соответствия идентификатора. Затем агрегируйте по идентификатору пользователя!

Пример.

 SELECT `user_id`,
  MAX(IF(`attribute`.`at_id`=`user`.`u_at1`,`attribute`.`at_text`,NULL)) as `u_at1_value`,
  MAX(IF(`attribute`.`at_id`=`user`.`u_at2`,`attribute`.`at_text`,NULL)) as `u_at2_value`, 
  MAX(IF(`attribute`.`at_id`=`user`.`u_at3`,`attribute`.`at_text`,NULL)) as `u_at3_value`,
  MAX(IF(`attribute`.`at_id`=`user`.`u_at4`,`attribute`.`at_text`,NULL)) as `u_at4_value`
FROM `user`,`attribute` 
GROUP BY `user_id`
 

С точки зрения производительности, я думаю, что быстрее использовать подзапросы для каждого поля, хотя из-за оптимизатора MySQL.

 SELECT `user_id`,
  (SELECT `at_text` FROM `attribute` WHERE `user`.`u_at1` = `attribute`.`at_id`) as `u_at1_value`,
  (SELECT `at_text` FROM `attribute` WHERE `user`.`u_at2` = `attribute`.`at_id`) as `u_at2_value`,
  (SELECT `at_text` FROM `attribute` WHERE `user`.`u_at3` = `attribute`.`at_id`) as `u_at3_value`,
  (SELECT `at_text` FROM `attribute` WHERE `user`.`u_at4` = `attribute`.`at_id`) as `u_at4_value`
FROM `user`
 

Ответ №2:

Я думаю, что это не очень хороший подход. Вы можете получить много повторяющихся результатов, если идентификаторы атрибутов одинаковы для разных идентификаторов. Более того, 20 левых соединений в СУБД сделают вашу базу данных покрытой коркой и являются нереалистичным подходом. Чтобы решить вашу проблему, вы можете изменить дизайн базы данных.

 user table:
user_id
attribute_id
 

И

 Attribute table:
    attribute_id,
    text1_column
    text2_column
    text3_column
    ....
    .....
    text20_column
 

Затем вы просто выполняете одно соединение, выбираете данные из своей базы данных. Обработайте и в каком столбце вы найдете данные, используйте их в соответствии с вашими потребностями.
Я не говорю, что это лучшее решение, но, по крайней мере, это значительно уменьшит вашу сложность.

Комментарии:

1. спасибо за ваш комментарий. Повторяющегося результата можно избежать, добавив псевдоним столбца. Но моя главная забота-это производительность для 20 левых соединений.

2. вы правы насчет повторяющихся результатов. А что касается производительности, то существует огромная вероятность того, что ваше приложение застрянет, а база данных будет заблокирована в течение длительного времени, что нежелательно. Для каждого левого соединения сложность увеличивается, как этот MxN1xN2x….N20, который, я полагаю, вам вообще не нужен в вашей системе!