Как эффективно применить МИНУС к запросу mysql для таблиц с большими данными

#mysql #query-optimization #large-data

#mysql #оптимизация запроса #большие данные

Вопрос:

У меня есть 2 таблицы в виде следующих —

 CREATE TABLE IF NOT EXISTS `nl_members` (
  `member_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `member_email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `member_confirmation_code` varchar(35) COLLATE utf8_unicode_ci NOT NULL,
  `member_enabled` enum('Yes','No') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Yes',
  PRIMARY KEY (`member_id`),
  UNIQUE KEY `TUC_nl_members_1` (`member_email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=58520 ;

CREATE TABLE IF NOT EXISTS `nl_member_group_xref` (
  `group_id` int(10) unsigned NOT NULL,
  `member_id` int(10) unsigned NOT NULL,
  `member_subscribed` enum('Yes','No') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Yes',
  `subscribe_date` int(10) unsigned NOT NULL DEFAULT '0',
  `unsubscribe_date` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`group_id`,`member_id`),
  KEY `nl_members_nl_member_group_xref` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


ALTER TABLE `nl_member_group_xref`
 ADD CONSTRAINT `nl_members_nl_member_group_xref` FOREIGN KEY (`member_id`) REFERENCES `nl_members` (`member_id`),
 ADD CONSTRAINT `nl_member_groups_nl_member_group_xref` FOREIGN KEY (`group_id`) REFERENCES `nl_member_groups` (`group_id`);
  

Оба имеют довольно большой объем данных о миллионах из них.

Что я хочу, так это иметь эффективный способ применения МИНУСА к результирующему набору.

Например,

я хочу получить всех пользователей из Group1 с ID: 1 МИНУС всех пользователей из Group2 с ID: 2 и Group3 с ID: 3

Как я могу сделать это эффективно? при этом запрос выполняется как можно быстрее.

Обновить

Чего я хочу, так это —

в таблице members ‘nl_members’ я храню список всех участников, которые могли быть связаны с одной или несколькими группами.

для каждой ассоциации группы для члена будет строка в таблице ‘nl_member_group_xref’.

таким образом, если элемент связан с 3 группами, в таблице member_group_xref будет 3 записи.

Теперь я хочу включить всех участников в группу 1, но исключить участников, если они также принадлежат к группе 2 и группе 3.

Надеюсь, это поможет.

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

1. У вас есть существующий запрос? Если вы говорите, что хотите минус для всех пользователей из групп2 и 3 в 1, я думаю, что это числовой результат. Но вы говорите «все пользователи», тогда это означает данные для каждого пользователя. Итак, я понимаю ваш вопрос так: LIMIT = 0,(G1 — (G2 G3)) где limit будет включен в конце вашего запроса. Если я неправильно понимаю, не могли бы вы объяснить это подробнее?

Ответ №1:

Для вашего обновленного вопроса вам нужно будет объединить две таблицы и сгруппировать их с помощью members_id: См. Ниже запрос, если отобразит искомый результат.

ОБНОВЛЕНО:

   SELECT 
         nm.*, nmgx.*
    FROM nl_members nm
   INNER JOIN nl_member_group_xref nmgx
      ON nm.member_id = nmgx.member_id
    LEFT JOIN (SELECT 
                      nmgx2.member_id
                 FROM nl_member_group_xref nmgx2
                WHERE nmgx2.group_id <> 1) nmgx22
      ON nmgx22.member_id = nm.member_id
   WHERE nmgx22.member_id IS NULL
   GROUP BY nm.member_id;
  

Примечание: я использовал *, чтобы получить все имена полей. Вы получаете определенное поле, поэтому запрос будет выполняться быстрее, поскольку он дает только меньше результатов. Например. member_id, такой как nm.member_id

Если это не то, что вы ищете, просто сообщите мне, тогда я обновлю этот запрос настолько точно, насколько смогу

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

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

2. Спасибо за ответ. но это не то, что я ищу. это простое внутреннее объединение, но необходимо найти членов group1 МИНУС все члены group2 и group3

3. @anjan, я обновляю свой пост, взгляните. Я надеюсь, что это то, что вы ищете, что касается оптимизации, я не уверен, что это быстрее, чем с вашим текущим рабочим запросом.

4. спасибо 🙂 я попробую и дам вам знать

Ответ №2:

Вы пробовали использовать оператор MINUS?

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

1. При очень большом наборе данных минус отнимет вдвое больше времени, так как придется извлекать оба результирующих набора, а затем устранять дубликаты

2. OP спрашивает об уменьшении наборов, а не чисел. В MySQL нет оператора EXCEPT / MINUS в этом смысле.