带有连接和group by子句的选择查询中的MySQL性能问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带有连接和group by子句的选择查询中的MySQL性能问题相关的知识,希望对你有一定的参考价值。

查询约700,000条记录的表时,我面临性能问题。对于特定的item_id,查询首次执行将花费10秒钟以上的时间,如果我更改查询中的item_id值,则查询将花费几乎相同的时间来执行。但是,除非重新启动服务器,否则后续查询相同的item_id的速度很快。

我要执行的查询是-

select SQL_NO_CACHE item_id, item_rate_id, invoice_type, sum(qty_computed) as qty
from transaction_item 
left join transaction_customer
       on transaction_item.invoice_id = transaction_customer.invoice_id 
where item_id = 17179
group by item_rate_id, invoice_type

我的表(InnoDB)的结构是-

表:transaction_item(无主键,索引:item_id,包含大约700,000行)

enter image description here

表transaction_customer(主键:invoice_id,包含大约100,000行)enter image description here

上面查询的运行说明给出了以下输出:

enter image description here

my.ini配置

[mysqld]
query_cache_size=0
query_cache_type=0
innodb_buffer_pool_size = 1G

高度赞赏有关微调MySQL config / db模式的任何帮助。

答案

格式化的可读性查询,但也添加了别名,因此将来的某人不必猜测哪个列来自哪个表。

无论如何,为了帮助优化查询,您需要一个复合索引来帮助where,join和order by。

我将在(item_id,item_rate_id,invoice_id)在您的Transaction_Item表上创建索引

此外,在您的Transaction_Customer表上,在(Invoice_id,Invoice_Type)上有一个索引

select SQL_NO_CACHE 
        ti.item_id, 
        ti.item_rate_id, 
        tc.invoice_type, 
        sum(ti.qty_computed) as qty
    from 
        transaction_item ti
            left join transaction_customer tc
                on ti.invoice_id = tc.invoice_id 
    where 
        ti.item_id = 17179
    group by 
        ti.item_rate_id, 
        tc.invoice_type
另一答案

请注意您的解释中的using filesort。我认为这是因为您使用的MySQL版本低于8.0。在这些版本中,结果由GROUP BY子句隐含地排序,大约为2500行。这会增加少量查询时间。

建议1:在查询中添加ORDER BY NULL以删除排序。

您的索引对于您描述的查询来说还不错。损害您的性能的是,这两个表的每一行都有大量数据。该查询需要来自每个表的元素,这些元素不在二级索引中,因此与指定项目相关的表的大块数据必须位于innodb缓冲池中。我没有看确切的数字,但是1G似乎还不够,您对查询的描述第二次变得更快似乎支持了这一点(尤其是在SQL_NO_CACHE和查询缓存被禁用的情况下(很好的是,它被禁用了) 。

建议2:增大innodb_buffer_pool的大小。查看SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool%',然后查看两次查询之间从缓冲区清除的项目数。

如果您确实对可用的RAM感到困惑,并遵循索引上@Drapp建议的主题,将允许仅将索引而不是整个表用于innodb缓冲池。此innodb_buffer_pool正在与其他查询竞争,因此以下内容对全局影响有限。

建议3 :(如果无法完成#2)

ALTER TABLE transaction_item
DROP INDEX item_id
ADD INDEX item_id (item_id, item_rate_id, qty_computed );

ALTER TABLE transaction_customer
ADD INDEX id_type (invoice_id, invoice_type);

以上是关于带有连接和group by子句的选择查询中的MySQL性能问题的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在具有GROUP BY子句的查询中选择非聚合列,而GROUP BY子句在功能上不依赖于GROUP BY子句中的列?

oracle group by 性能优化

如何从表中选择带有 oracle sql 中的 group by 子句的嵌套 json 对象?

选择不在 GROUP BY 子句中的列

如何在没有附加查询的情况下在 SQL Server 中连接没有子查询的 GROUP BY 子句中的字符串?

SQL Server报错:选择列表中的列无效,因为该列没有包含在聚合函数或 GROUP BY 子句中