sql 分組查詢前N名

分組查詢前十名

表結構html

CREATE TABLE `tb_api_app_income_rank` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_id` varchar(64) DEFAULT '',
  `product_name` varchar(255) DEFAULT NULL,
  `publisher_id` varchar(64) DEFAULT NULL,
  `publisher_name` varchar(512) DEFAULT NULL,
  `company_id` varchar(64) DEFAULT NULL,
  `company_name` varchar(512) DEFAULT NULL,
  `category` varchar(64) DEFAULT NULL COMMENT '分類',
  `rank_type` varchar(32) DEFAULT NULL COMMENT '排行榜類型,0:免費,1:付費,2:暢銷',
  `country` varchar(32) DEFAULT NULL,
  `rank` int(11) DEFAULT NULL COMMENT '在收入下載量排行榜的排名',
  `change_rank` int(11) DEFAULT NULL,
  `change_percent` decimal(11,6) DEFAULT NULL,
  `change_value` int(11) DEFAULT NULL,
  `price` decimal(11,2) DEFAULT NULL,
  `estimate` int(11) DEFAULT NULL,
  `downloads` int(11) DEFAULT NULL COMMENT '下載量',
  `income` int(11) DEFAULT NULL COMMENT '收入',
  `release_date` varchar(32) DEFAULT NULL,
  `is_new` int(11) DEFAULT '0' COMMENT '是否新品,0:不是,1:是。新品:距離當前時間往前推7天(昨日爲第7日),release date在這7天以內,且該產品的appid是首次出現,纔算作新品',
  `created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`,`created_at`),
  KEY `idx_apir_update_time` (`updated_at`) USING BTREE,
  KEY `idx_apir_ctime_country` (`country`,`created_at`) USING BTREE,
  KEY `idx_apir_aid` (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=52188 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='app 收入下載量的排行榜,分免費、付費、暢銷排行榜'
  1. 第一種方案
SELECT
    t1.*
FROM
    tb_api_app_income_rank t1
WHERE
    created_at = '2017-11-07 00:00:00'
AND rank_type = 'grossing'
AND change_rank = 1000
AND (
    SELECT
        count(1)
    FROM
        tb_api_app_income_rank
    WHERE
        rank_type = 'grossing'
    AND change_rank = 1000
    AND created_at = '2017-11-07 00:00:00'
    AND country = t1.country
    AND category = t1.category
    AND rank < t1.rank
) < 3;

消耗時間: 7.260smysql

  1. 第二種方案
SELECT
    t1.*
FROM
    tb_api_app_income_rank t1
left join  tb_api_app_income_rank t2 ON t2.created_at = '2017-11-07 00:00:00'
AND t2.rank_type = 'grossing'
AND t2.change_rank = 1000
AND t1.country = t2.country
AND t1.category = t2.category
AND t1.rank > t2.rank
where t1.created_at = '2017-11-07 00:00:00'
AND t1.rank_type = 'grossing'
AND t1.change_rank = 1000
group by t1.country, t1.category, t1.product_id
having count(t1.product_id)<3
order by t1.country, t1.category,rank;

消耗時間: 8.076ssql

  1. 第三種
select * from 
(SELECT
    (
        @i := CASE
        WHEN @pre_country = country && @pre_category = category THEN
            @i + 1
        ELSE
            1
        END
    ) rownum,
    t1.*, (@pre_country := country), (@pre_category := category)
FROM
    tb_api_app_income_rank t1,
    (
        SELECT
            @i := 0,
            @pre_country := '',
            @pre_category := ''
    ) AS tmp
WHERE
    created_at = '2017-11-07 00:00:00'
AND rank_type = 'grossing'
AND change_rank = 1000
ORDER BY
    country,
    category,
    rank) t2 where t2.rownum <=3

消耗時間: 0.113sapi

由上得出結論,使用遊標而不是連表或嵌套子查詢,速度快翻幾千倍app

參考資料

  1. mysql分組排序加序號(不用存儲過程,就簡簡單單sql語句哦)
  2. mysql分組取每組前幾條記錄(排序)
  3. mysql分組取每組前幾條記錄(排名) 附group by與order by的研究
  4. SQL怎麼取出每一個科目前三名並按科目和分組排列
相關文章
相關標籤/搜索