MySQL運維實戰系列:MySQL5.7GroupBy問題
一、環境
MySQL版本:MySQL5.7.22
表結構:
CREATE TABLE `crm_report_accounting_income` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`contract_id` int(10) NOT NULL,
`contract_no` varchar(50) NOT NULL,
`date` int(8) NOT NULL,
`city_id` int(11) NOT NULL DEFAULT `0` COMMENT `城市id`,
`city_name` varchar(50) DEFAULT NULL,
`adviser_id` int(10) NOT NULL,
`adviser_name` varchar(50) DEFAULT NULL,
`accounting` decimal(15,2) NOT NULL COMMENT `xx`,
`receivable` decimal(15,2) NOT NULL DEFAULT `0.00` COMMENT `當xx`,
`contract_type` tinyint(1) NOT NULL DEFAULT `1` COMMENT `1:xx合同;2:xx合同;3:xx合同`,
PRIMARY KEY (`id`),
KEY `contract_id` (`contract_id`),
KEY `date` (`date`),
KEY `city_id` (`city_id`)
) ENGINE=InnoDB AUTO_INCREMENT=734525 DEFAULT CHARSET=utf8
二、業務問題
* 基本資訊,由於合同號太多,所以這邊就以一個有重複資料的合同id為例
dba:aif_db> select contract_id,contract_no,receivable,date from crm_report_accounting_income_2015_online where contract_id = 27310;
+-------------+----------------------------+------------+----------+
| contract_id | contract_no | receivable | date |
+-------------+----------------------------+------------+----------+
| 27310 | A00-SHEN-05-2018-06-004613 | 2941.18 | 20180628 |
| 27310 | A00-SHEN-05-2018-06-004613 | 5882.36 | 20180629 |
| 27310 | A00-SHEN-05-2018-06-004613 | 8823.54 | 20180630 |
| 27310 | A00-SHEN-05-2018-06-004613 | 11764.72 | 20180701 |
| 27310 | A00-SHEN-05-2018-06-004613 | 14705.90 | 20180702 |
| 27310 | A00-SHEN-05-2018-06-004613 | 17647.08 | 20180703 |
| 27310 | A00-SHEN-05-2018-06-004613 | 20588.26 | 20180704 |
| 27310 | A00-SHEN-05-2018-06-004613 | 23529.44 | 20180705 |
| 27310 | A00-SHEN-05-2018-06-004613 | 26470.62 | 20180706 |
| 27310 | A00-SHEN-05-2018-06-004613 | 29411.80 | 20180707 |
| 27310 | A00-SHEN-05-2018-06-004613 | 32352.98 | 20180708 |
| 27310 | A00-SHEN-05-2018-06-004613 | 35294.16 | 20180709 |
+-------------+----------------------------+------------+----------+
12 rows in set (0.00 sec)
* 查詢每個最新合同的資訊,由於合同號太多,所以這邊就以一個有重複資料的合同id為例
select contract_no, contract_id, city_name, receivable,date from
(select * from crm_report_accounting_income_2015_online where contract_id = 27310 ORDER BY `date` desc) p GROUP BY contract_id
+----------------------------+-------------+-----------+------------+----------+
| contract_no | contract_id | city_name | receivable | date |
+----------------------------+-------------+-----------+------------+----------+
| A00-xxxx-05-2018-06-xxxxxx | xxxxx | 瀋陽 | 2941.18 | 20180628 |
+----------------------------+-------------+-----------+------------+----------+
1 row in set (0.00 sec)
以上看到的寫法,是通過子查詢寫的,5.6查詢沒問題,5.7就變成了以上的結果,很明顯得到的答案不是業務想要的
究其原因還是因為,MySQL5.7 sql mode更加嚴格了,如果設定sql_mode = ONLY_FULL_GROUP_BY, 那麼以上SQL就會報錯
因為sql_mode = ONLY_FULL_GROUP_BY 要求符合SQL 92標準,即:select列表裡只能出現分組列(即group by後面的列)和聚合函式(max,min等等)
然而為了相容5.6,我們設定sql_mode=“, 所以我們的Group by 在子查詢中就跟5.6就不一致了
當然,我們應該避免不標準的SQL寫法,這樣的問題,我們的解法就是調整業務的SQL語句,改寫成SQL 92標準的語法
那麼以上SQL語句應該調整為:
select
contract_no,
e.contract_id,
city_name,
receivable,
date
from
crm_report_accounting_income_2015_online e,
( select contract_id , max(date) max_date from crm_report_accounting_income_2015_online where contract_id = 27310 group by contract_id ) t
where
e.contract_id = t.contract_id
and e.date = t.max_date
+----------------------------+-------------+-----------+------------+----------+
| contract_no | contract_id | city_name | receivable | date |
+----------------------------+-------------+-----------+------------+----------+
| A00-xxxx-05-2018-06-004613 | 27310 | xxxx | 35294.16 | 20180709 |
+----------------------------+-------------+-----------+------------+----------+
1 row in set (0.00 sec)
以上都還是需要業務程式碼修改,這樣如果沒有提前發現問題,豈不是會導致業務出錯了?有沒有更好的辦法?
MySQL方面其實還是可以配置相關的引數的:
dba:aif_db> set optimizer_switch=`derived_merge=off`;
Query OK, 0 rows affected (0.00 sec)
dbadmin:aifangcrm_db> select contract_no, contract_id, city_name, receivable,date from
-> (select * from crm_report_accounting_income_2015_online where contract_id = 27310 ORDER BY `date` desc) p GROUP BY contract_id
-> ;
+----------------------------+-------------+-----------+------------+----------+
| contract_no | contract_id | city_name | receivable | date |
+----------------------------+-------------+-----------+------------+----------+
| A00-xxxx-05-2018-06-004613 | 27310 | xxxx | 35294.16 | 20180709 |
+----------------------------+-------------+-----------+------------+----------+
1 row in set (0.00 sec)
三、總結
- SQL語法應該要按照標準的SQL92來寫
- 資料庫升級到5.7之後,應該提前監控處group by + 子查詢的情況,提前告知業務修改業務程式碼
- 設定引數也能解決問題,但是這個引數畢竟是5.7新增的,如果關閉後,以後會不會導致其他的bug就不知曉了
最後,還是希望能夠修改query 語句到標準語法,如果出現業務問題,可以讓業務修改引數快速解決問題,然後再修改語句比較與時俱進
相關文章
- MySQL5.7GTID運維實戰MySql運維
- MySQL運維實戰(7)建立複製MySql運維
- Istio 運維實戰系列(1):應用容器對 Envoy Sidecar 的啟動依賴問題運維IDE
- MySQL運維實戰(7.1) 開啟GTID複製MySql運維
- 網易OpenStack部署運維實戰運維
- 運維排查問題常用sql運維SQL
- MYSQL實戰-MHA搭建及問題總結MySql
- 三、實戰系列問題處理集中營
- kafka 運維中遇到的問題Kafka運維
- MySQL運維實戰(5.6) 字符集設定對mysqldump的影響MySql運維
- Istio 運維實戰系列(2):讓人頭大的『無頭服務』-上運維
- Istio 運維實戰系列(3):讓人頭大的『無頭服務』-下運維
- MySQL運維實戰(二)之巧用P_S解決賬號host訪問的榮耀王者之路MySql運維
- mysql運維案例MySql運維
- 「實戰篇」開源專案docker化運維部署-搭建mysql叢集(四)Docker運維MySql
- MySQL運維實戰之備份和恢復(8.1)xtrabackup全量備份MySql運維
- 實戰!聊聊如何解決MySQL深分頁問題MySql
- ElasticSearch實戰系列十一: ElasticSearch錯誤問題解決方案Elasticsearch
- NodeJS 實戰系列:DevOps 尚未解決的問題NodeJSdev
- 如何實現MySQL運維體系建設MySql運維
- 掌握運維必備技能--問題故障定位運維
- Redis運維實戰之叢集中的腦裂Redis運維
- MATLAB實戰系列(十)-二維裝箱問題之BL法修正版(附MATLAB程式碼)Matlab
- MySQL基礎運維——percona-toolkit運維工具MySql運維
- MySQL 8.0能徹底解決困擾運維的複製延遲問題!MySql運維
- MySQL運維實戰(6)使用者認證外掛caching_sha2_passwordMySql運維
- redis持久化開發運維常見問題Redis持久化運維
- 《CentOS 8系統管理與運維實戰》簡介CentOS運維
- 《IT運維之道》——3.4落實整體運維運維
- 實戰前端跨域問題前端跨域
- 專案實戰小問題:
- SSM實戰教程(小問題)SSM
- 運維常見軟體問題排查與修復運維
- 運維實戰:騰訊雲會展安全的“勢”“道”“術”運維
- MySQL運維5-Mycat配置MySql運維
- 測試平臺系列(85) 把redis運用到實戰中Redis
- 運維必備-解決鎖問題的全過程運維
- 該怎麼解決運維定位服務故障問題?運維