MySQL查询在复合键表上运行非常慢

MySQL查询在复合键表上运行非常慢,mysql,performance,Mysql,Performance,我有一个组合键表CUSTOMER\u PRODUCT\u XREF __________________________________________________________________ |CUSTOMER_ID (PK NN VARCHAR(191)) | PRODUCT_ID(PK NN VARCHAR(191))| ------------------------------------------------------------------- SELECT

我有一个组合键表CUSTOMER\u PRODUCT\u XREF

__________________________________________________________________
|CUSTOMER_ID (PK NN VARCHAR(191)) | PRODUCT_ID(PK NN VARCHAR(191))|
-------------------------------------------------------------------
SELECT 
    customer.*, group_concat(xref.PRODUCT_ID separator ', ')
FROM
    CUSTOMER customer
LEFT JOIN CUSTOMER_PRODUCT_XREF xref ON customer.CUSTOMER_ID=xref.CUSTOMER_ID  
group by customer.CUSTOMER_ID 
LIMIT 500;
在我的批处理程序中,我需要选择500个更新的客户,还需要获得客户购买的产品ID(用逗号分隔),并更新我们的SOLR索引。在我的查询中,我选择了500个客户,并与客户\产品\外部参照进行左连接

__________________________________________________________________
|CUSTOMER_ID (PK NN VARCHAR(191)) | PRODUCT_ID(PK NN VARCHAR(191))|
-------------------------------------------------------------------
SELECT 
    customer.*, group_concat(xref.PRODUCT_ID separator ', ')
FROM
    CUSTOMER customer
LEFT JOIN CUSTOMER_PRODUCT_XREF xref ON customer.CUSTOMER_ID=xref.CUSTOMER_ID  
group by customer.CUSTOMER_ID 
LIMIT 500;
编辑:解释查询

id  select_type table   type    possible_keys   key      key_len    ref     rows    Extra
1   SIMPLE     customer ALL      PRIMARY        NULL     NULL       NULL    74236   Using where; Using temporary; Using filesort
1   SIMPLE      xref    index     NULL          PRIMARY  1532       NULL    121627  Using where; Using index; Using join buffer (Block Nested Loop)
运行上述查询20分钟后,我遇到了连接丢失异常

我尝试了以下(子查询),结果花了1.7秒,但仍然很慢

SELECT 
customer.*, (SELECT group_concat(PRODUCT_ID separator ', ') 
     FROM CUSTOMER_PRODUCT_XREF xref 
        WHERE customer.CUSTOMER_ID=xref.CUSTOMER_ID
        GROUP BY customer.CUSTOMER_ID) 
FROM
CUSTOMER customer
LIMIT 500;
编辑:解释查询结果

id  select_type          table      type    possible_keys   key    key_len  ref     rows   Extra
1   PRIMARY              customer     ALL       NULL        NULL    NULL    NULL    74236   NULL
2   DEPENDENT SUBQUERY    xref      index        NULL     PRIMARY   1532    NULL    121627 Using where; Using index; Using temporary; Using filesort
问题

CUSTOMER\u PRODUCT\u XREF已经将两列都设置为PRIMARY\u KEY和NOT\u NULL,但是为什么我的查询仍然非常慢?我认为在列上有主键就足以为它建立索引。我需要进一步索引吗

数据库信息:

  • 我数据库中的所有ID都是VARCHAR(191),因为ID可以包含字母
  • 我正在使用utf8mb4\uUnicode\uCI字符编码
  • 我正在使用集合组\u concat\u max\u len:=@@max\u allowed\u packet为每个客户获取最大数量的产品\u ID。更喜欢在一个主查询中使用group_concat,这样我就不必进行多个单独的查询来获得每个客户的产品
原始版本的查询首先执行
连接,然后对所有结果数据进行排序——考虑到字段的大小,这可能相当大

您可以通过先选择500个客户,然后执行加入操作来“修复”该版本:

SELECT c.*, group_concat(xref.PRODUCT_ID separator ', ')
FROM (select c.*
      from CUSTOMER customer c
      order by c.customer_id
      limit 500
     ) c LEFT JOIN
     CUSTOMER_PRODUCT_XREF xref
     ON c.CUSTOMER_ID=xref.CUSTOMER_ID  
group by c.CUSTOMER_ID ;
另一种可能有很大影响,也可能没有很大影响的方法是在子查询中按客户进行聚合,并将其加入,如:

SELECT c.*, xref.products
FROM (select c.*
      from CUSTOMER customer c
      order by c.customer_id
      limit 500
     ) c LEFT JOIN
     (select customer_id, group_concat(xref.PRODUCT_ID separator ', ') as products
      from CUSTOMER_PRODUCT_XREF xref
     ) xref
     ON c.CUSTOMER_ID=xref.CUSTOMER_ID;

您发现MySQL优化器没有意识到这种情况(限制对性能有很大影响)。在这种情况下,其他一些数据库引擎在优化方面做得更好。

好吧,当我仅在CUSTOMER\u PRODUCT\u外部参照表中的CUSTOMER\u ID上创建索引时,我问题中的查询速度加快了

我现在有两个索引 产品ID和客户ID的主键索引
CUSTOMER\u ID上的CUSTOMER\u ID\u INDEX

使用该命令运行查询并将该命令的结果添加到问题中,它将帮助人们(和您)了解发生了什么。但说真的,191个字符的主键?你确定这不是一个滑跑过度吗?:-)尝试在CUSTOMER\u PRODUCT\u外部参照上创建一个非唯一索引,仅包括CUSTOMER\u id列。使用INT主键(191个字符的键是另一列,相关表使用INT键而不是LONG键)可能更有效(从长远来看)。在数据库设计方面,您可以使用自动增量代理键作为客户表和产品表上的主键。您仍然可以保留原始的长客户id和产品id,每个id上都有一个唯一的索引。然后,在customer\u product\u xref中只能有一对整数的行,这将使比较变得更小更快。@fvu我添加了解释查询输出:)我认为字段的默认大小无关紧要。我应该减小大小吗?第一个查询花费了1.45秒,第二个查询没有返回任何结果。在我的问题中,第一次查询耗时1.30秒,第二次查询耗时54秒。我已经将CUSTOMER\u PRODUCT\u XREF主键的VARCHAR id长度更改为20个字符,但仍然非常慢:(@CMR…我不知道你为什么会皱眉头。你正在学习MySQL优化器的工作原理。我对相关子查询在MySQL中工作良好并不感到惊讶,这并不意味着它在其他数据库中工作良好。