Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Оптимизация MYSQL запроса
 
 автор: p.pavluxa   (29.08.2012 в 17:34)   письмо автору
 
 

Здравствуйте, уважаемые пользователи форума.

Имеется такая таблица:

CREATE TABLE IF NOT EXISTS `PrivateMessages` (
  `iID` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '№',
  `sCreateDate` datetime NOT NULL COMMENT 'Дата и время отправки',
  `iSenderID` int(10) unsigned NOT NULL COMMENT '№ отправителя',
  `sMessage` text NOT NULL COMMENT 'Сообщение',
  `iRecipientID` int(10) unsigned NOT NULL COMMENT '№ получателя'
  PRIMARY KEY (`iID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Приватные сообщения' AUTO_INCREMENT=1 ; 


И вот такой запрос для обращения к ней:

SELECT * , IF( `iSenderID` = <userid>, `iRecipientID` , `iSenderID` ) AS `iCorrespondentID` 
FROM (
    SELECT * 
    FROM `PrivateMessages` 
    WHERE `iSenderID` = <userid> OR `iRecipientID` = <userid>
    ORDER BY `iID` DESC 
) AS `t` 
GROUP BY `iCorrespondentID` 


Как мы видим этот запрос является вложенным, что не есть хорошо для скорости его работы при больших объемах данных.

Помогите с него сделать два отдельных запроса по ключу. Заранее спасибо.

  Ответить  
 
 автор: cheops   (30.08.2012 в 07:08)   письмо автору
 
   для: p.pavluxa   (29.08.2012 в 17:34)
 

А цель какая? Получить последнее письмо <userid> направленное ему или от него? Если да, то может поступить следующим образом?
SELECT
  *,
  IF( `iSenderID` = <userid>, `iRecipientID` , `iSenderID` ) AS `iCorrespondentID`  
FROM
  `PrivateMessages`  
WHERE
  `iSenderID` = <userid> OR `iRecipientID` = <userid>
ORDER BY
  `iID` DESC  
LIMIT 1

  Ответить  
 
 автор: p.pavluxa   (30.08.2012 в 10:08)   письмо автору
 
   для: cheops   (30.08.2012 в 07:08)
 

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

  Ответить  
 
 автор: Sfinks   (30.08.2012 в 11:19)   письмо автору
 
   для: p.pavluxa   (29.08.2012 в 17:34)
 

Во-первых, без подзапроса тут не обойтись.
Во-вторых, объединяя вопрос из этой темы и из вашей же соседней, мне кажется ваш запрос не выполняет поставленной задачи.
И вообще он не правильный, т.к. у вас в селекте присутствуют поля (SELECT *) отсутствующие в предикате GROUP BY.
Для меня является большой тайной, почему MySQL не выдает на это ошибку, но работают такие конструкции не правильно - это точно. Т.е. в выдаче поля отсутствующие в GROUP BY могут принадлежать любой строке из группы.

Простой пример:
Тавлица:
CREATE TABLE tbl ( `id` int(10), `date` timestamp ) ENGINE=MyISAM

Данные:
INSERT INTO tbl VALUES(10,'2012-08-20 10:00:00'),(3,'2012-08-20 10:00:00'),(5,'2012-08-20 10:00:00')

Запрос:
SELECT * FROM tbl GROUP BY `date`

Вопрос:
Что вернет запрос? А главное - ПОЧЕМУ?

Правильный запрос должен в списке SELECT содержать только поля из GROUP BY. Все другие поля могут использоваться только с агрегатными функциями!
Например такой запрос:
SELECT max(id), `date` FROM tbl GROUP BY `date`
однозначно вернет:
10 | 2012-08-20 10:00:00


Теперь вернемся к вашему запросу и попробуем сделать его правильным.
/*<?*/
SELECT iSenderID
     
iRecipientID
     
max(`date`)dt
     
/* кореллирующий подзапрос */
       
SELECT sMessage
         FROM PrivateMessages
         WHERE 
( (iSenderID = <userid> AND iRecipientID=pm.iRecipientID) OR
                 (
iRecipientID = <userid> AND iSenderID=pm.iSenderID) ) AND
               `
date`=max(pm.`date`)
         
LIMIT 1 /* ограничение на случай, если имеется несколько подходящих строк */
       
)ms
FROM PrivateMessages pm
WHERE iSenderID 
= <userid> OR iRecipientID = <userid>
GROUP BY iSenderIDiRecipientID

Но по большому счету и этот запрос не совсем верный.
Например если имеются такие данные:
INSERT INTO PrivateMessages VALUES
(1,'2012-08-20 10:00:00',10,'Привет',20),
(2,'2012-08-20 10:00:00',20,'Пока',10)
, т.е. два пользователя написали друг другу одновременно, то для пользователя <10> будет выведено:
10 | 20 | 2012-08-20 10:00:00 | 'Привет'
20 | 10 | 2012-08-20 10:00:00 | 'Привет'
, что, как вы понимаете, не верно.

Считаю, что после такой лекции у меня есть моральное право дать вам "домашнее задание" исправить этот запрос =)))
_____________
[UPD]
Перепрятушки =)
Запрос вернет все правильно. Но он для пользователя <userid>, если с пользователем например <20> есть и входящие и исходящие, выведет последнее входящее и последнее исходящее.
Если вам нужно только одно последнее сообщение, не важно вход-е или исход-е, то попробуйте исправить сами =)
Но вложенность запросов придется еще увеличить!

  Ответить  
 
 автор: p.pavluxa   (31.08.2012 в 10:34)   письмо автору
 
   для: Sfinks   (30.08.2012 в 11:19)
 

Эм... Не понял почему мой запрос работает неверно

  Ответить  
 
 автор: Sfinks   (31.08.2012 в 23:10)   письмо автору
 
   для: p.pavluxa   (31.08.2012 в 10:34)
 

Ну я уж и не знаю что тут еще добавить!...
Ну проверьте свой запрос на таких данных:
INSERT INTO `PrivateMessages` (`iID`, `sCreateDate`, `iSenderID`, `sMessage`, `iRecipientID`) VALUES
(NULL, '2012-08-31 00:00:00', '10', 'последнее сообщение', '20'),
(NULL, '2012-08-22 00:00:00', '10', 'первое сообщение', '20'),
(NULL, '2012-08-26 00:00:00', '10', 'промежуточное сообщение', '20');
для <userid>=10 и проверьте мой (только исправьте в нем везде `date` на sCreateDate - я опечатался) и сравните результат.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования