2009-07-29 22 views
1

私はという2つのクエリを取得しています。はmysqlデータベースから、1つは動作しますが、私の質問は「なぜですか?Mysqlサブ選択問題

問題:最初のクエリを実行する場合 、MySQLサーバは、100%のCPU使用率を取得し、再び機能を再起動しなければなりません。

クエリ1(動作しない):

SELECT tags.*, COUNT(ct.company_id) AS count 
FROM company2tag ct, tags 
WHERE ct.company_id IN (
    SELECT ct.company_id FROM company2tag ct 
    WHERE ct.tag_id = 18 
    GROUP BY ct.company_id 
    HAVING COUNT(ct.company_id) = 1 
) 
AND tags.id != 18 
AND tags.id = ct.tag_id 
GROUP BY ct.tag_id 
ORDER BY count DESC 
LIMIT 5; 

クエリ2(作品):

SELECT tags.*, COUNT(ct.company_id) AS count 
FROM company2tag ct, tags 
WHERE ct.company_id IN (5864, 5870, 6140, 6221, 6268) 
    AND tags.id != 18 
    AND tags.id = ct.tag_id 
GROUP BY ct.tag_id 
ORDER BY count DESC 
LIMIT 5; 

は、私の理解するには、上記の2つのクエリが完全に同じことを行う、唯一の最初の問合せが副選択を介してその「company_id」を検索するという違いがあります。

どうすればいいですか?

+0

サブクエリはどのように単独で動作しますか? – paxdiablo

+0

は完全に動作し、company_idのリストを返します。 – smoove

+0

SQLが有効でないために2番目のクエリがどのように機能するかわかりません。集計関数ではない選択されたすべてのフィールドは、GROUP BYリスト(あなたの場合はタグ。*)に存在する必要があります。 – Tihauan

答えて

3

まず最初に、外側のクエリに1つ、サブクエリに1つのct ...という名前の2つのテーブルがあるため、最初のクエリで問題が発生する可能性があります。私は実際にこれをテストしていない

SELECT tags.*, COUNT(ct.company_id) AS count 
FROM company2tag ct 
INNER JOIN tags ON tags.id = ct.tag_id 
INNER JOIN (
    SELECT company_id FROM company2tag 
    WHERE tag_id = 18 
    GROUP BY company_id 
    HAVING COUNT(company_id) = 1 
) ctf ON ct.company_id = ctf.company_id 
WHERE tags.id != 18 
GROUP BY ct.tag_id 
ORDER BY count DESC 
LIMIT 5; 

注:

第二に、あなたが登録しようとしてを書き換えることができます。

+0

+1はJOINとしてINを書き直すことに言及しています。 INは、短いリストと照合するためのものです。あなたが他のテーブル/クエリに基づいてより大きいリストを持っているなら、それはJOINでなければなりません。 –

+0

ありがとう!ソリューションは約10倍高速で、サーバーをブロックしません。 – smoove

2

MySQLは、INの条件をあまり良くしていません。

最初のクエリの条件をEXISTSと簡単に書き換えることはできません。そのため、MySQLは各行の結果をチェックします。ここでの主なアイデアは、あなたがCOUNT(*)する必要がないことです

SELECT tags.*, COUNT(company_id) AS count 
FROM company2tag ct 
JOIN tags 
ON  tags.id = ct.tag_id 
WHERE ct.tag_id <> 18 
     AND NOT EXISTS 
     (
     SELECT NULL 
     FROM company2tag cti 
     WHERE cti.tag_id = 18 
       AND cti.company_id = ct.company_id 
     LIMIT 1, 1 
     ) 
GROUP BY 
     ct.tag_id 
ORDER BY 
     count DESC 

:あなたはtag 18で複数回言及されているcompany_id年代を選択したい場合は

は、それのようなこの問合せをリライトする方が良いでしょう少なくとも2つの値が存在することを確認するだけで十分です。

CREATE INDEX ix_company2tag_tag_company_id ON company2tag (tag_id, company_id) 

が大幅にこのクエリを改善します:以下の屈折率を有する

は、同様の問題のために私のブログでこの記事を参照してください。