MySQL - SELECT, убрать дубли, оптимизировать при 2х JOIN

Статус
В этой теме нельзя размещать новые ответы.

Горбушка

Ищу её...
Регистрация
2 Май 2008
Сообщения
3.444
Реакции
2.524
Есть запрос:
Код:
SELECT 
 `u`.*,
 `c`.`title` AS `city`,
 `p`.`title` AS `phone`
FROM
 `clients` AS `u`
LEFT JOIN
 (SELECT `title`, `client_id` FROM `clients_contacts` WHERE `type` = 1) AS `c`
 ON
 `u`.`id` = `c`.`client_id`
LEFT JOIN
 (SELECT `title`, `client_id` FROM `clients_contacts` WHERE `type` = 3) AS `p`
 ON
 `p`.`client_id` = `u`.`id`;

Нужно оптимизировать и убрать дубли...

В настоящий момент если у человека 2 телефона и 2 города (типы 3 и 1 соответственно) - происходит вывод 4 строк, а надо выводить только 2...

Так же по возможности реализовать с минимальной нагрузкой на БД.

P.s. этот запрос работает, но выводит слишком много лишнего :) При 100 городах и 100 телефонах у 1 клиента будет 10 000 строчек на 1 человека, а надо 100.

Код:
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `clients`
-- ----------------------------
DROP TABLE IF EXISTS `clients`;
CREATE TABLE `clients` (
  `id` int(9) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) CHARACTER SET utf8 NOT NULL,
  `type` int(2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

-- ----------------------------
-- Records of clients
-- ----------------------------
INSERT INTO `clients` VALUES ('1', 'Нежность', '1');
INSERT INTO `clients` VALUES ('2', 'Иванова Инна Ивановна', '2');
INSERT INTO `clients` VALUES ('3', 'Сидорова Инна Ивановна', '2');

-- ----------------------------
-- Table structure for `clients_contacts`
-- ----------------------------
DROP TABLE IF EXISTS `clients_contacts`;
CREATE TABLE `clients_contacts` (
  `id` int(9) NOT NULL AUTO_INCREMENT,
  `client_id` int(9) NOT NULL,
  `title` varchar(255) CHARACTER SET utf8 NOT NULL,
  `type` int(2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;

-- ----------------------------
-- Records of clients_contacts
-- ----------------------------
INSERT INTO `clients_contacts` VALUES ('1', '1', '1', '1');
INSERT INTO `clients_contacts` VALUES ('2', '1', 'Петровка 38', '2');
INSERT INTO `clients_contacts` VALUES ('3', '2', '1', '1');
INSERT INTO `clients_contacts` VALUES ('4', '1', '9001234567', '3');
INSERT INTO `clients_contacts` VALUES ('5', '1', 'admin@test.ru', '4');
INSERT INTO `clients_contacts` VALUES ('6', '1', '2', '1');
INSERT INTO `clients_contacts` VALUES ('7', '1', '9001231231', '3');
INSERT INTO `clients_contacts` VALUES ('8', '2', '9001231231', '3');
INSERT INTO `clients_contacts` VALUES ('9', '3', '2', '1');
 
Последнее редактирование:
GROUP BY `phone` в конце не подойдет?
 
1 телефон может быть у 2 и более людей. Не прокатит, по идеи...
 
  • Заблокирован
  • #4
хех, ну вот, советы повторяются. мы в чятике уже обсудили проблему:
один джойн вместо двух с обьединенным через дизьюнкцию условием не пойдет (кстати, можно же туда добавить OR `type` is null),
group by в конце не пойдет, мы пробовали по айди делать. Я, правда, не помню, почему он не сработал. group by очень логичный выход при дублях.
есть вариант с дополнительным select'ом вот в этом where:
ну и в симметричном, конечно. Но это очень неэффективный метод.

Можно поиграться с where в глобальном селекте.
Я бы делал через stored procedure, что может быть гораздо эффективней. Единственная альтернатива - переписывание джойнов, по ходу.
1 телефон может быть у 2 и более людей. Не прокатит, по идеи...
вообще, груп бай надо делать по ключевому, или другому уникальному полю. по айди. айди же у всех один, верно?

Вообще, имхо, такая хрень случается, когда таблицы проектирует вася, который не понимает, что такое третья нормальная форма. выучили два запроса и ффперед базы таблички клепать.
 
Да херня вопрос - таблицы можно переписывать как хочешь )))

Проектировал их я... Но когда их проектировал, такой задачи не стояло.
 
  • Заблокирован
  • #6
когда проектируешь любые таблицы для любого бизнеса, ты хочешь всюду всегда соблюдать третью нормальную форму. Если не получается, ты делаешь дополнительные таблицы, которые позволяют это делать. В таком случае тебе не пришлось бы делать два одновременных джойна одной и той же таблицы. Мне никогда в жизни такого не приходилось делать. по моему, это явный свидетель проблем с проектированием.

это как некоторые любители прокладывают локальную сеть для бизнеса на витой паре, выстроив пары так, как им понравилось, а не по стандарту. потом что-то летит, приходит специалист и охреневает от такой витой пары.
 
Давай данных тогда побольше, испытывать не на чем, вообще сама структура базы не сильно понятна.
Кстати, в 90% случаев сложная выборка джойнами работает медленней чем постобработка в скрипте пусть даже с серией дополнительных запросов.
 
  • Заблокирован
  • #8
Кстати, в 90% случаев сложная выборка джойнами работает медленней чем постобработка в скрипте пусть даже с серией дополнительных запросов.
учитывая, что двиг мускуля гораздо серьезней двига пыхи, если сравнивать их по оптимизированности, я бы сказал наоборот: если ты делаешь в пыхе то, что можно сделать в мускуле, в 95% случаев ты тупишь.

ЗЫ

а, вообще, да, горбушка, давай дампы базы.
 
учитывая, что двиг мускуля гораздо серьезней двига пыхи, если сравнивать их по оптимизированности, я бы сказал наоборот: если ты делаешь в пыхе то, что можно сделать в мускуле, в 95% случаев ты тупишь.
Да хрен там, для самых примитивных джойнов эта скотина любит создавать временные таблицы (Using temporary; Using filesort), я уже молчу про всякие RAND(), WHERE IN SELECT.... и т.п. Сколько уж раз проверял - красиво в один запрос, далеко не всегда быстро.
 
  • Заблокирован
  • #10
Да хрен там, для самых примитивных джойнов эта скотина любит создавать временные таблицы (Using temporary; Using filesort), я уже молчу про всякие RAND(), WHERE IN SELECT.... и т.п. Сколько уж раз проверял - красиво в один запрос, далеко не всегда быстро.
ну так да, джойн - это временная таблица, и что? селект - тоже временная таблица. а что не так с рендомом? В итоге, нагрузку все хотят убрать с проца и передать оперативке, когда можно. всегда. это основа оптимизации кода. Посему, если нам нужна еще одна таблица в памяти ценой процессора - мы в 90% случаев ее хотим там.

ЗЫ
у нас сейчас закончится дурацкая дневная порция постов и мы не сможем продолжать обсуждение.
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху