數據表結構和數據以下:php
CREATE TABLE `commun_message_chat_single` ( `id` int(11) NOT NULL AUTO_INCREMENT, `chat_id` int(11) DEFAULT '0' COMMENT '會話id', `from_id` varchar(11) DEFAULT NULL COMMENT '發送者 用戶id', `to_id` varchar(11) DEFAULT NULL COMMENT '接收者 用戶id', `content` text COMMENT '消息內容', `type` tinyint(1) DEFAULT '1' COMMENT '消息類型 1:文字 2:圖片 3:文件', `send_time` datetime DEFAULT NULL COMMENT '消息發送時間', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='單聊 聊天記錄'; -- 插入數據的sql INSERT INTO `commun_message_chat_single` VALUES (60, 10, '11', 'md_1', '123', 1, '2019-10-16 08:25:50'); INSERT INTO `commun_message_chat_single` VALUES (61, 10, '11', 'md_1', '456', 1, '2019-10-28 08:25:59'); INSERT INTO `commun_message_chat_single` VALUES (62, 10, '11', 'md_2', '789', 1, '2019-10-01 08:26:21'); INSERT INTO `commun_message_chat_single` VALUES (63, 10, '11', 'md_2', '哈哈哈', 1, '2019-10-27 08:26:34'); INSERT INTO `commun_message_chat_single` VALUES (64, 10, '11', 'md_2', '測試測試', 1, '2019-10-10 08:28:27');
目前數據表全部數據以下:mysql
mysql> select * from commun_message_chat_single where from_id = '11'; +----+---------+---------+-------+--------------+------+---------------------+ | id | chat_id | from_id | to_id | content | type | send_time | +----+---------+---------+-------+--------------+------+---------------------+ | 60 | 10 | 11 | md_1 | 123 | 1 | 2019-10-16 08:25:50 | | 61 | 10 | 11 | md_1 | 456 | 1 | 2019-10-28 08:25:59 | | 62 | 10 | 11 | md_2 | 789 | 1 | 2019-10-01 08:26:21 | | 63 | 10 | 11 | md_2 | 哈哈哈 | 1 | 2019-10-27 08:26:34 | | 64 | 10 | 11 | md_2 | 測試測試 | 1 | 2019-10-10 08:28:27 | +----+---------+---------+-------+--------------+------+---------------------+ 5 rows in set (0.00 sec)
需求:查詢from_id爲11的數據 而且 和 每個to_id 按照時間排序顯示最新的一條數據(也就是顯示:to_id是md_1的,按照時間排序id爲61的符合結果;to_id是md_2的,按照時間排序id爲63的符合結果)sql
符合該需求的2條數據以下:數據庫
+----+---------+---------+-------+-----------+------+---------------------+ | id | chat_id | from_id | to_id | content | type | send_time | +----+---------+---------+-------+-----------+------+---------------------+ | 61 | 10 | 11 | md_1 | 456 | 1 | 2019-10-28 08:25:59 | | 63 | 10 | 11 | md_2 | 哈哈哈 | 1 | 2019-10-27 08:26:34 | +----+---------+---------+-------+-----------+------+---------------------+
實現該需求的sql語句以下(利用sql中的子查詢):sqlserver
SELECT * FROM (SELECT * FROM commun_message_chat_single WHERE from_id = '11' ORDER BY send_time DESC ) as temp_table GROUP BY temp_table.to_id; -- 大概解釋下該條sql語句:括號內的子查詢是查詢from_id爲11的數據而且按照send_time從高到低排序,這裏的子查詢的結果會生成一個臨時表,臨時表這裏取名爲temp_table,而後外部查詢將temp_table的結果進行分組。
mysql5.7版本如下執行結果以下(只在5.5和5.6版本試過):測試
+----+---------+---------+-------+-----------+------+---------------------+ | id | chat_id | from_id | to_id | content | type | send_time | +----+---------+---------+-------+-----------+------+---------------------+ | 61 | 10 | 11 | md_1 | 456 | 1 | 2019-10-28 08:25:59 | | 63 | 10 | 11 | md_2 | 哈哈哈 | 1 | 2019-10-27 08:26:34 | +----+---------+---------+-------+-----------+------+---------------------+ 2 rows in set (0.00 sec)
mysql5.7版本執行結果以下:優化
+----+---------+---------+-------+---------+------+---------------------+ | id | chat_id | from_id | to_id | content | type | send_time | +----+---------+---------+-------+---------+------+---------------------+ | 60 | 10 | 11 | md_1 | 123 | 1 | 2019-10-16 08:25:50 | | 62 | 10 | 11 | md_2 | 789 | 1 | 2019-10-01 08:26:21 | +----+---------+---------+-------+---------+------+---------------------+ 2 rows in set (0.00 sec)
what?爲啥5.7如下的版本是咱們想要的結果,而5.7版本的執行結果竟然不是咱們期待的結果!高版本竟然執行的結果不正確。。spa
爲何mysql5.7和5.7如下的版本會有不一樣的結果呢?code
能夠分別查看一下這條sql語句在兩個不一樣版本數據庫的sql執行計劃: server
mysql 5.7.21:
mysql5.5.62和5.6.44:
對比能夠發現5.7版本的mysql在執行這條sql語句的時候缺乏了一個derived的操做,經過查閱相關資料瞭解到mysql5.7對子查詢進行了優化,認爲子查詢中的order by能夠進行忽略,只要Derived table裏不包含以下條件就能夠進行優化:
①、UNION clause
②、GROUP BY
③、DISTINCT
④、Aggregation
⑤、LIMIT or OFFSET
看到了吧,若是要在mysql5.7中實現先排序後分組,這裏能夠加個limit,不過你的limit要足夠大
mysql5.7解決辦法以下:
SELECT * FROM (SELECT * FROM commun_message_chat_single WHERE from_id = '11' ORDER BY send_time DESC LIMIT 10000 ) as temp_table GROUP BY temp_table.to_id;
mysql8.0及以上版本沒試過,不過應該和5.7是同樣的效果,都進行了優化。
PS:子查詢不是mysql獨有的,sqlserver等數據庫也能夠使用子查詢