本文為博主原創,轉載請注明出處:
mysql使用group by可以使用一些聚合函數,可以計算最大值(max(column)),最小值(min(column)),總和(sum(column)),平均數(avg(column()))等等,
在使用聚合函數的函數的時候,我們只可以查詢聚合函數相關的列,其余的列則不能進行查詢。示例如下:
表結構如下:
CREATE TABLE `fucdn_hot_rank_domain` ( `id` int(12) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `domain` int(11) NOT NULL COMMENT '域名id', `band` double NOT NULL COMMENT '帶寬,單位為B', `total` int(16) NOT NULL COMMENT '請求數', `clock` varchar(255) NOT NULL COMMENT '時間', PRIMARY KEY (`id`), UNIQUE KEY `domain` (`domain`,`clock`), KEY `domain_id` (`domain`) ) ENGINE=InnoDB AUTO_INCREMENT=21961394 DEFAULT CHARSET=utf8 COMMENT='域名用量熱門排行表';
使用聚合函數查詢非聚合列:
查詢非聚合列的時候異常提示:
which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by,不在聚合函數之內,查詢異常。
如果要查詢非聚合函數的列,可以再嵌套一遍進行關聯查詢,
使用如下:
這種查詢的方便之處在於它可以避免寫多個sql進行多次查詢,但如果需要查詢的時候有多條,則需要手動過濾一下。項目中用到的sql如下:
select clock, band, total,domain from ( select MAX(band)as band1,domain from fucdn_hot_rank_domain where domain in(11612,11613,11614,11615,11616,11617,11618,11619,11620) and clock BETWEEN '2019-10-20 00:00:00.0' and '2019-10-20 23:59:59.0' GROUP BY domain ORDER BY band1 desc limit 20 )t join fucdn_hot_rank_domain fhrd on t.band1=fhrd.band and t.domain= fhrd.domain ORDER BY domain
之前代碼中要查詢這些數據的時候是分批次查詢的,先查詢所有數據,再根據過濾出的所有域名,計算出對應的峰值以及峰值時間。
代碼都是用的流式計算,由於數據量大,計算相對還是比較慢的,后來優化為上面的sql后,性能比之前快了兩倍多。
原來實現的代碼如下,以供警醒,哈哈
@Override public List<HotRankDomainResult> getHotRankDomainList(DomainCodeHelper helper) throws FucdnException { List<HotRankDomainResult> resultList = new ArrayList<>(); System.out.println("<<<<<<<<<<<<<<selectTime::"+new Date()); List<HotRankHelper> helperList = hotRankDao.getHotRankDomainList(helper); System.out.println(">>>>>>>>>>>>>>selectEndTime::"+new Date()); // 計算出域名帶寬峰值,峰值時間,總流量,總請求數等 // 1.獲取域名列表 List<String> domainList = helperList.stream().map(HotRankHelper::getDomain).collect(Collectors.toList()); // 2.對域名列表去重 domainList = domainList.stream().distinct().collect(Collectors.toList()); for (String domain : domainList) { HotRankDomainResult resultDetail = new HotRankDomainResult(); // 獲取域名對應的列表數據 List<HotRankHelper> domainResultList = helperList.stream() .filter((HotRankHelper flow) -> domain.equals(flow.getDomain())).collect(Collectors.toList()); // 計算峰值 domainResultList = domainResultList.stream().sorted(Comparator.comparing(HotRankHelper::getBand).reversed()) .collect(Collectors.toList()); // 計算總流量和請求數 double totalFlow = domainResultList.stream().collect(Collectors.summingDouble(HotRankHelper::getBand)); int totalRequest = domainResultList.stream().collect(Collectors.summingInt(HotRankHelper::getTotal)); // 獲取峰值數據 HotRankHelper topHelper = domainResultList.get(0); resultDetail.setMaxBand(topHelper.getBand()); resultDetail.setMaxBandTime(topHelper.getClock()); resultDetail.setDomain(topHelper.getDomain()); resultDetail.setTotalFlow(totalFlow); resultDetail.setTotalRequest(Integer.toString(totalRequest)); resultList.add(resultDetail); } // 對集合進行排序:降序 resultList = resultList.stream().sorted(Comparator.comparing(HotRankDomainResult::getMaxBand).reversed()) .collect(Collectors.toList()); if (resultList.size() > 20) { // 獲取前20 resultList = resultList.subList(0, 20); } System.out.println(">>>>>>>>>>>>>>sortEndTime::"+new Date()); return resultList; }