0

这个查询:

SELECT `subscribers`.`email_address`, `subscribers`.`first_name`, `subscribers`.`last_name`,
        GROUP_CONCAT( DISTINCT t1.value SEPARATOR '|' ) AS 'Colors', GROUP_CONCAT( DISTINCT t2.value SEPARATOR '|' ) AS 'Languages'
FROM `subscribers`
LEFT JOIN `subscribers_multivalued` AS `t1` ON subscribers.subscriber_id = t1.subscriber_id AND t1.field_id = 112
LEFT JOIN `subscribers_multivalued` AS `t2` ON subscribers.subscriber_id = t2.subscriber_id AND t2.field_id = 111
WHERE (list_id = 40) AND (state = 1)
GROUP BY `subscribers`.`email_address` , `subscribers`.`first_name` , `subscribers`.`last_name`

使用执行计划:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  subscribers     ref     FK_list_id,state_date_added     FK_list_id  4   const   1753610     Using where; Using filesort
1   SIMPLE  t1  ref     subscriber_fk,field_fk  subscriber_fk   4   chad0598_mailablel.subscribers.subscriber_id    1    
1   SIMPLE  t2  ref     subscriber_fk,field_fk  subscriber_fk   4   chad0598_mailablel.subscribers.subscriber_id    1    

由于未知原因导致错误:一般错误:3 在 mysql 中写入文件“/tmp/MYzamaNT”(错误代码:28)时出错。

我通过subscriber_id insead 把它改写成这样的groupy:

SELECT `subscribers`.`email_address`, `subscribers`.`first_name`, `subscribers`.`last_name`,
        GROUP_CONCAT( DISTINCT t1.value SEPARATOR '|' ) AS 'Colors', GROUP_CONCAT( DISTINCT t2.value SEPARATOR '|' ) AS 'Languages'
FROM `subscribers`
LEFT JOIN `subscribers_multivalued` AS `t1` ON subscribers.subscriber_id = t1.subscriber_id AND t1.field_id = 112
LEFT JOIN `subscribers_multivalued` AS `t2` ON subscribers.subscriber_id = t2.subscriber_id AND t2.field_id = 111
WHERE (list_id = 40) AND (state = 1)
GROUP BY `subscribers`.`subscriber_id`

这个查询的计划更好(不是文件排序):

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  subscribers     ref     FK_list_id,state_date_added     FK_list_id  4   const   1753610     Using where
1   SIMPLE  t1  ref     subscriber_fk,field_fk  subscriber_fk   4   chad0598_mailablel.subscribers.subscriber_id    1    
1   SIMPLE  t2  ref     subscriber_fk,field_fk  subscriber_fk   4   chad0598_mailablel.subscribers.subscriber_id    1   

它似乎在 mysql 中工作,并且比以前的查询快得多。虽然它可以在 mysql 中使用,但它不符合 sql 标准,但不应在字段列表中包含 GROUP BY 中不存在的聚合字段。我有办法使查询与最后一个查询一样快并使其符合 sql 吗?

我也尝试用这种方式重写它:

SELECT `subscribers`.`email_address`, `subscribers`.`first_name`, `subscribers`.`last_name`,
        t1.colors AS 'Colors', t2.languages AS 'Languages'
FROM `subscribers`
LEFT JOIN (SELECT subscriber_id, GROUP_CONCAT( DISTINCT value SEPARATOR '|' ) AS 'colors'
           FROM subscribers_multivalued
           WHERE field_id = 112
           GROUP BY subscriber_id)  t1 ON t1.subscriber_id = `subscribers`.`subscriber_id`
LEFT JOIN (SELECT subscriber_id, GROUP_CONCAT( DISTINCT value SEPARATOR '|' ) AS 'languages'
           FROM subscribers_multivalued
           WHERE field_id = 111
           GROUP BY subscriber_id)  t2 ON t2.subscriber_id = `subscribers`.`subscriber_id`         

这个查询的计划要糟糕得多:

1   PRIMARY     subscribers     ALL     NULL    NULL    NULL    NULL    23358546     
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    900000   
1   PRIMARY     <derived3>  ALL     NULL    NULL    NULL    NULL    900000   
3   DERIVED     subscribers_multivalued     ALL     field_fk    field_fk    4       20621115    Using filesort
2   DERIVED     subscribers_multivalued     ALL     field_fk    field_fk    4       20621115    Using filesort

我等不及它返回数据了;

4

1 回答 1

2

我会保留更快的。您还可以测试/基准测试此变体:

SELECT s.email_address, 
       s.first_name, 
       s.last_name,
       COALESCE(t1.Colors, '') AS Colors,
       COALESCE(t2.Languages, '') AS Languages
FROM subscribers AS s
  LEFT JOIN 
    ( SELECT t1.subscriber_id, 
          GROUP_CONCAT( DISTINCT t1.value SEPARATOR '|' ) AS Colors
      FROM subscribers AS s
        JOIN subscribers_multivalued AS t1
          ON s.subscriber_id = t1.subscriber_id 
      WHERE t1.field_id = 112
        AND s.list_id = 40 
        AND s.state = 1
      GROUP BY t1.subscriber_id 
    ) AS t1
    ON s.subscriber_id = t1.subscriber_id 
  LEFT JOIN 
    ( SELECT t2.subscriber_id, 
             GROUP_CONCAT( DISTINCT t2.value SEPARATOR '|' ) AS Languages
      FROM subscribers AS s
        JOIN subscribers_multivalued AS t2
          ON s.subscriber_id = t2.subscriber_id 
      WHERE t2.field_id = 111
        AND s.list_id = 40 
        AND s.state = 1
      GROUP BY t2.subscriber_id 
    ) AS t2
    ON s.subscriber_id = t2.subscriber_id 
WHERE s.list_id = 40 
  AND s.state = 1 ;

如果(field_id, subscriber_id, value)在表中是唯一的subscribers_multivalued,也可以去掉这两个DISTINCT


关于速度和效率,请检查您拥有的索引。这些将对您的版本和这个版本都有帮助:

  • subscribers表中,一个索引(list_id, state, subscriber_id)要么(state, list_id, subscriber_id)

  • 在表中,或 (次佳) 上subscribers_multivalued的索引。(field_id, subscriber_id, value)(field_id, subscriber_id)

于 2012-11-02T15:53:29.043 回答