【问题标题】:Optimize MySQL query "count(*)" with "group by" clause使用“group by”子句优化 MySQL 查询“count(*)”
【发布时间】:2020-07-07 15:05:30
【问题描述】:

我使用的是 MySQL 5.7,下面的 sql 运行大约 10+ 秒,而总共只有 60K 数据,并且没有多少列,我不明白为什么它执行这么长时间。 为了优化 SQL,我添加了索引并更新了 SQL,但是没有用。

研究:当我删除 where 子句时,它运行 400ms,添加它并删除 count(*) 后,它也需要 400ms。

SELECT adt.data_source_id AS groupName, count(1) AS count
    FROM assets_data_table adt
    WHERE adt.is_deleted = 0
      AND adt.tenant_id = 2
      AND adt.sync_status = 1
    GROUP BY adt.data_source_id;

如下所示显示我的表格 DDL:

create table assets_data_table
(
    id bigint unsigned auto_increment comment 'pk'
        primary key,
    create_at datetime default CURRENT_TIMESTAMP not null comment 'create date',
    update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 'update date',
    create_by int default 0 not null ,
    update_by int default 0 not null ,
    is_deleted tinyint(1) default 0 not null comment '1 deleted,0 undeleted',
    table_name varchar(100) not null ,
    table_name_cn varchar(100) null ,
    data_source_id bigint not null ,
    sync_status tinyint(1) default 0 not null ,
    db_id bigint not null ,
    schema_name varchar(100) null ,
    table_storage bigint default 0 not null ,
    table_owner bigint default 0 not null ,
    table_hot bigint default 0 not null ,
    extra_attribute json null comment 'json string',
    origin_table_id varchar(32) null ,
    tenant_id bigint not null ,
    sync_date datetime null ,
    table_create_at datetime null 
)
comment 'table';
# added to optimize sql
create index assets_data_table_ck
    on assets_data_table (is_deleted, tenant_id, sync_status);
# added to optimize sql
create index assets_data_table_ck_1
    on assets_data_table (is_deleted, tenant_id, sync_status, data_source_id);

create index idx_datasource_id
    on assets_data_table (data_source_id);

create index idx_dbid
    on assets_data_table (db_id);

解释:

| id | select\_type | table | partitions | type | possible\_keys | key | key\_len | ref | rows | filtered | Extra |
| 1 | SIMPLE | adt | NULL | ref | idx\_datasource\_id,assets\_data\_table\_ck,assets\_data\_table\_ck\_1 | assets\_data\_table\_ck\_1 | 10 | const,const,const | 28218 | 100 | Using where; Using index |

在此处附上查询结果:

我的优化: 使用子查询,第一步:选择需要的列; 2.使用group by子句。它可以使用索引,只需要 400ms 执行。

SELECT adt.data_source_id AS groupName, count(*) AS count
FROM (select is_deleted, tenant_id, sync_status, data_source_id from assets_data_table
      WHERE is_deleted = 0
        AND tenant_id = 2
        AND sync_status = 1) adt
GROUP BY adt.data_source_id;

| id | select\_type | table | partitions | type | possible\_keys | key | key\_len | ref | rows | filtered | Extra |

| 1 | SIMPLE | assets\_data\_table | NULL | ref | idx\_datasource\_id,assets\_data\_table\_ck,assets\_data\_table\_ck\_1 | assets\_data\_table\_ck\_1 | 10 | const,const,const | 28218 | 100 | Using where; Using index |

我的问题:

  1. 是否有其他方法可以优化此查询?
  2. group by 子句是如何工作的,为什么在我使用子查询之后它可以通过索引,它可以以其他方式使用索引吗?

谢谢!

【问题讨论】:

    标签: mysql indexing group-by count


    【解决方案1】:
    WHERE adt.is_deleted = 0
      AND adt.tenant_id = 2
      AND adt.sync_status = 1
    GROUP BY adt.data_source_id;
    

    需要一个 4 列的复合索引:

     INDEX(is_deleted, tenant_id, sync_status, -- in any order
           data_source_id)   -- last
    

    而且,由于只使用了这 4 列,因此索引是“覆盖”的,因此它的速度可能是 scaisEdge 答案的两倍。 “覆盖”由EXPLAIN中的“使用索引”(不是“使用索引条件”)表示。

    嵌套查询建议不太可能帮助任何人。 (在其他情况下它确实有帮助。)

    如果你有两者

    (is_deleted, tenant_id, sync_status)
    (is_deleted, tenant_id, sync_status, data_source_id)
    

    第一个是“冗余”。此外,当第二个更好时,优化器可能会错误地使用第一个。

    BIGINT 很庞大(8 个字节)。缩小它可能会有所帮助。

    【讨论】:

    • 谢谢 Rick,正如你所说,第一个索引被使用,第二个被优化器忽略,我删除第一个,然后重新运行原始 SQL,第二个索引工作。
    • @KDFinal - 感谢您的反馈。您对使用“第二个”索引的速度有多快有感觉吗?
    【解决方案2】:

    您的查询应该返回与此相同的值

    select data_source_id, count(*)
    from assets_data_table
    WHERE is_deleted = 0
    AND tenant_id = 2
    AND sync_status = 1
    group by data_source_id
    

    并确保您有适当的复合索引

    create index  myidx on assets_data_table ( tenant_id , sync_status, is_deleted )
    

    【讨论】:

      猜你喜欢
      • 2020-03-18
      • 2015-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多