› MySQL 5.5 Community Server
› MySQL 5.6 Community Server
› Percona Configuration Wizard
› XtraBackup 搭建主从复制
Great Sites on MySQL
› Percona
› MySQL Performance Blog
› Severalnines
推荐管理工具
› Sequel Pro
› phpMyAdmin
推荐书目
› MySQL Cookbook
MySQL 相关项目
› MariaDB
› Drizzle
参考文档
› http://mysql-python.sourceforge.net/MySQLdb.html
test523
V2EX  ›  MySQL

MySQL group by 优化

  •  1
     
  •   test523 · Jan 28, 2022 · 4926 views
    This topic created in 1745 days ago, the information mentioned may be changed or developed.

    目的取一段时间内 uid 对应消耗,然后划分区间

    发现 group by uid返回的数据越多越慢,这个从 SQL 下手有优化空间吗

    MySQL 5.7
    
    select
      elt(interval(total, null, 300), '-INF~300', '300~INF') as section,
      count(*) AS total
    from (
      select
        uid,
        SUM(gold) as total
      from `table_name`
      where `time` > 1640966400 and `time` <= 1642176000 group by `uid`
    ) as `tmp` group by `section`;
    
    -- 执行了 3-4 秒
    
    返回结果:
    -INF~300	46319
    300~INF		15060
    

    EXPLAIN 结果:

    select_type table type possible_keys rows rows
    PRIMARY <derived2> ALL 217073 Using temporary; Using filesort
    DERIVED table_name index time,uid 434146 Using where
    Supplement 1  ·  Jan 28, 2022

    附上表结构

    CREATE TABLE `table_name` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `time` int(11) unsigned NOT NULL DEFAULT '0',
      `uid` bigint(20) unsigned NOT NULL DEFAULT '0',
      `gold` bigint(20) unsigned NOT NULL DEFAULT '0',
      PRIMARY KEY (`id`),
      KEY `time` (`time`),
      KEY `uid` (`uid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
    
    16 replies  •  2022-02-08 17:34:27 +08:00
    enjoychen0318
    enjoychen0318
    Jan 28, 2022
    1
    加个 order by null 试试?
    test523
    test523
    OP
    Jan 28, 2022
    2
    @enjoychen0318 作用不大,还是很慢
    xshell
    xshell
    Jan 28, 2022
    3
    没走索引
    Gota
    Gota
    Jan 28, 2022
    4
    猜测省掉一次 group 会不会好一点? 不过我没数据也不好试, 写出来大概是这样.

    select
    SUM(lt300) as lt300,
    SUM(gt300) as gt300
    from (
    select
    IF(SUM(gold) < 300, 1, 0) as lt300,
    IF(SUM(gold) < 300, 0, 1) as gt300
    from `table_name`
    where `time` > 1640966400 and `time` <= 1642176000
    group by `uid`
    ) as `tmp`
    blakejia
    blakejia
    Jan 28, 2022
    5
    select
    uid,
    SUM(gold) as total
    from `table_name`
    where `time` > 1640966400 and `time` <= 1642176000 group by `uid`

    第一层耗时多少秒?
    sanggao
    sanggao
    Jan 28, 2022
    6
    time 加索引,并且 force use time 这个索引
    test523
    test523
    OP
    Jan 28, 2022
    7
    @blakejia 第一层 3 秒左右

    @sanggao time
    test523
    test523
    OP
    Jan 28, 2022
    8
    @sanggao 刚才不小心点错了,

    time 是有索引,FORCE INDEX(time)后耗时减少 1s
    galileo1214
    galileo1214
    Jan 28, 2022
    9
    开窗?
    blakejia
    blakejia
    Jan 28, 2022
    10
    整表有多少数据量呢?
    23fksd
    23fksd
    Jan 28, 2022
    11
    联合索引+覆盖:CREATE INDEX idx_uid_time_gold ON table_name (uid,`time`,gold);
    Masonnn
    Masonnn
    Jan 29, 2022
    12
    可以,就在这个帖子里学到了 elt()、interval()、force index()
    a222QAQ
    a222QAQ
    Jan 29, 2022 via Android
    13
    @sweetsorrow211 学习+1
    opengps
    opengps
    Jan 30, 2022
    14
    我理解,time 和 uid 应该是个联合索引
    whoisix
    whoisix
    Feb 7, 2022
    15
    mark ,学习+1
    thinkmore
    thinkmore
    Feb 8, 2022
    16
    尝试建立下 index(time,uid ,gold)联合索引,不知道是否可以提供数据供分析
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1647 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 13:20 · PVG 21:20 · LAX 05:20 · JFK 08:20
    ♥ Do have faith in what you're doing.