Для простоты приведем таблицу сообщений к минимуму с некоторыми примерами данных
message_id reply_to createdate
1 0 123
2 0 124
3 0 123
4 1 154
5 1 165
reply_to - это message_id, сообщение которого является ответом на
так что я ищу sql-оператор / процедуру / функцию / другой дизайн таблицы, который позволил бы мне выбрать последние 10 сообщений и для каждого из них последние 3 ответа, я не против изменить структуру таблицы или даже сохранить какой-то вид запись за последние 3 ответа
просто выберите последние 10 сообщений
SELECT * FROM message ORDER BY createdate LIMIT 10;
и для каждого из этих сообщений ответы
SELECT * FROM message WHERE reply_to = :message_id: ORDER BY createdate LIMIT 3;
Мои попытки на данный момент:
- тройное внешнее соединение по таблице сообщений в ответах
- простое объединение, но mysql не допускает ограничений в объединениях
- использование HAVING COUNT (DISTINCT reply_to) <= 3, но конечно HAVING оценивается последним </li>
я не смог получить ни одного из тех, кто работал
моя последняя опция atm - иметь отдельную таблицу для отслеживания последних 3 ответов на сообщение
message_reply:
message_id, r_1, r_2, r_3
и затем обновление этой таблицы с использованием триггеров
поэтому новая строка в таблице сообщений, которая является ответом, обновляет таблицу message_reply
UPDATE message_reply SET r_3 = r_2, r_2 = r_1, r_1 = NEW.reply_to WHERE message_id = NEW.message_id
тогда я мог бы просто запросить таблицу сообщений для этих записей
у кого-нибудь есть лучшее предложение или даже рабочий оператор SQL?
спасибо
EDIT:
добавлено ПОЯСНИТЬ результаты
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived4> ALL NULL NULL NULL NULL 3
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 10 Using where; Using join buffer
1 PRIMARY r eq_ref PRIMARY,message_id,message_id_2 PRIMARY 4 func 1
4 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
5 UNION NULL NULL NULL NULL NULL NULL NULL No tables used
6 UNION NULL NULL NULL NULL NULL NULL NULL No tables used
NULL UNION RESULT <union4,5,6> ALL NULL NULL NULL NULL NULL
2 DERIVED m ALL NULL NULL NULL NULL 299727
3 DEPENDENT SUBQUERY r ref reply_to,reply_to_2 reply_to_2 4 testv4.m.message_id 29973
РЕДАКТИРОВАТЬ 2:
Ну, я попробовал метод таблицы message_reply, и это то, что я сделал
построить таблицу:
message_reply: message_id, r_1, r_2, r_3
построить триггер:
DELIMITER |
CREATE TRIGGER i_message AFTER INSERT ON message
FOR EACH ROW BEGIN
IF NEW.reply_to THEN
INSERT INTO message_replies (message_id, r_1) VALUES (NEW.reply_to, NEW.message_id)
ON DUPLICATE KEY UPDATE r_3 = r_2, r_2 = r_1, r_1 = NEW.message_id;
ELSE
INSERT INTO message_replies (message_id) VALUES (NEW.message_id);
END IF;
END;
|
DELIMITER ;
и выберите сообщения:
SELECT m.*,r1.*,r2.*,r3.* FROM message_replies mr
LEFT JOIN message m ON m.message_id = mr.message_id
LEFT JOIN message r1 ON r1.message_id = mr.r_1
LEFT JOIN message r2 ON r2.message_id = mr.r_2
LEFT JOIN message r3 ON r3.message_id = mr.r_3
Конечно, триггер предварительно обрабатывает его для меня, это самый быстрый способ.
протестировано с еще несколькими наборами вставок по 100 Кб, чтобы увидеть снижение производительности для триггера
Обработка 100 тыс. строк заняла 0,4 секунды дольше, чем без Tirgger
общее время для вставки составило около 12 секунд (в таблицах myIsam)