0

私は実際にこれを機能させることができましたが、グルがより最適なアプローチを提供できるかどうか疑問に思っていました:

SELECT `cfc`.`card_face_id`
FROM `card_face_color` AS `cfc`
INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
WHERE c.c_url IN ('black', 'blue')
AND card_face_id NOT IN (
    SELECT `cfc`.`card_face_id`
    FROM `card_face_color` AS `cfc`
    INNER JOIN `color` AS `c` ON cfc.color_id = c.color_id
    WHERE c.c_url NOT IN ('black', 'blue')
)
GROUP BY `cfc`.`card_face_id`
HAVING (COUNT(DISTINCT c.c_url) = 2)

基本的に、黒と青を含むすべての card_faces を選択しようとしていますが、他の色は含まれていません (各 card_face は最大 5 つまで可能です)。内部結合を使用して実行しようとしましたが、これは 25 倍近く遅くなりました。私は自分のインデックスにかなり満足しています。私は、Having 句の経験が浅いだけです。

アップデート

クエリに対して実行EXPLAINすると、これが明らかになります(フォーマットについてはお詫びします)。

id select_type table type  possible_keys key      key_len ref                   rows Extra
1  PRIMARY     c      index PRIMARY,c_url c_url    50      NULL                  10   Using where; Using index; Using temporary; Using filesort
1  PRIMARY     cfc    ref   color_id      color_id 1       site.co.uk.c.color_id 1156 Using where; Using index
2  SUBQUERY    c      range PRIMARY,c_url c_url    50      NULL                  9    Using where; Using index
2  SUBQUERY    cfc    ref   color_id      color_id 1       site.co.uk.c.color_id 1156 Using index
4

2 に答える 2

1

これが別のアプローチです。最初に、結果セットを2色しかないカード面に制限してみました。パフォーマンスがもっと良いかどうか教えてください。

SELECT cfc2.card_face_id, COUNT(*) AS cardcount2
FROM card_face_color cfc2 
  INNER JOIN color c ON cfc2.color_id=c.color_id AND c.c_url IN ('black','blue')
  INNER JOIN (SELECT cfc.card_face_id, COUNT(*) AS cardcount
              FROM card_face_color cfc
              GROUP BY cfc.card_face_id
              HAVING cardcount=2) AS color_counter ON cfc2.card_face_id=color_counter.card_face_id
GROUP BY cfc2.card_face_id
HAVING cardcount2=2                                                              

アプローチ2

もう1つの壁を越えたアプローチ:

SELECT card_face_id, SUM(U.counter) AS counter FROM
(
SELECT cfc2.card_face_id, 1 AS counter
FROM card_face_color cfc2 
  INNER JOIN color c ON cfc2.color_id=c.color_id AND c.c_url IN ('black','blue')

UNION ALL

SELECT cfc2.card_face_id, 100 AS counter
FROM card_face_color cfc2 
  INNER JOIN color c ON cfc2.color_id=c.color_id AND NOT c.c_url IN ('black','blue')

) AS U
GROUP BY card_face_id
HAVING counter=2

アプローチ3 あなたがどれほど柔軟かはわかりませんが、このアプローチでは、内部結合を排除しました。

SET @blue_id = (SELECT color_id FROM color WHERE c_url='blue');
SET @black_id = (SELECT color_id FROM color WHERE c_url='black');

SELECT card_face_id, SUM(U.counter) AS counter FROM
(
SELECT cfc2.card_face_id, 1 AS counter
FROM card_face_color cfc2 
WHERE cfc2.color_id IN (@blue_id,@black_id)

UNION ALL

SELECT cfc2.card_face_id, 100 AS counter
FROM card_face_color cfc2 
WHERE cfc2.color_id NOT IN (@blue_id,@black_id)

) AS U
GROUP BY card_face_id
HAVING counter=2
于 2012-07-19T22:45:40.143 に答える
1

これがクエリのいくつかのバージョンです

  1. これは良いですか悪いですか?(〜30ms)
    group_concatによるフィルター

    SELECT `cfc`.`card_face_id`
    FROM `card_face_color` AS `cfc`
    INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
    GROUP BY `cfc`.`card_face_id`
    HAVING GROUP_CONCAT(c.c_url ORDER BY c.c_url) = 'black,blue'
    
  2. これはおそらくインデックスをより良く使用します(〜35ms)
    良い=2と悪い=0

    SELECT `cfc`.`card_face_id`
    FROM `card_face_color` AS `cfc`
    INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
    GROUP BY `cfc`.`card_face_id`
    HAVING
      SUM(IF(c.c_url IN ('black','blue'), 1, NULL)) = 2 AND
      SUM(IF(c.c_url IN ('black','blue'), NULL, 1)) = 0
    
  3. 2回目が失敗したので、今回はDISTINCTでもう一度試してみます(〜34ms)
    合計=2およびgood= 2

    SELECT `cfc`.`card_face_id`
    FROM `card_face_color` AS `cfc`
    INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
    GROUP BY `cfc`.`card_face_id`
    HAVING
      COUNT(DISTINCT c.c_url) = 2 AND
      COUNT(DISTINCT IF(c.c_url IN ('black','blue'), c.c_url, NULL)) = 2
    
  4. もう少しひねりましょう。
    合計=2、悪い=0です。

    SELECT `cfc`.`card_face_id`
    FROM `card_face_color` AS `cfc`
    INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
    GROUP BY `cfc`.`card_face_id`
    HAVING
      COUNT(DISTINCT c.c_url) = 2 AND
      COUNT(IF(c.c_url IN ('black','blue'), NULL, c.c_url)) = 0
    
  5. すべての組み合わせをテストするためだけに、
    good=2およびbad=0

    SELECT `cfc`.`card_face_id`
    FROM `card_face_color` AS `cfc`
    INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
    GROUP BY `cfc`.`card_face_id`
    HAVING
      COUNT(DISTINCT IF(c.c_url IN ('black','blue'), c.c_url, NULL)) = 2 AND
      COUNT(IF(c.c_url IN ('black','blue'), NULL, c.c_url)) = 0
    
于 2012-07-19T22:54:40.937 に答える