5

私の mysql DB は、特に遅いクエリを実行しようとして CPU を消費するようになりました。説明を行うと、mysql は「where の使用、temporary の使用、filesort の使用」と表示します。このパズルの解読と解決を手伝ってください。

テーブル構造:

CREATE TABLE `topsources` (
  `USER_ID` varchar(255) NOT NULL,
   `UPDATED_TIME` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `URL_ID` int(11) NOT NULL,
  `SOURCE_SLUG` varchar(100) NOT NULL,
  `FEED_PAGE_URL` varchar(255) NOT NULL,
  `CATEGORY_SLUG` varchar(100) NOT NULL,
  `REFERRER` varchar(2048) DEFAULT NULL,
  PRIMARY KEY (`USER_ID`,`URL_ID`),
  KEY `USER_ID` (`USER_ID`),
  KEY `FEED_PAGE_URL` (`FEED_PAGE_URL`),
  KEY `SOURCE_SLUG` (`SOURCE_SLUG`),
  KEY `CATEGORY_SLUG` (`CATEGORY_SLUG`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

テーブルには 370K 行あります...場合によってはそれ以上になります。以下のクエリには 10 秒以上かかります。

SELECT topsources.SOURCE_SLUG, COUNT(topsources.SOURCE_SLUG) AS VIEW_COUNT
FROM topsources
WHERE CATEGORY_SLUG = '/newssource'
GROUP BY topsources.SOURCE_SLUG
HAVING MAX(CASE WHEN topsources.USER_ID = 'xxxx' THEN 1 ELSE 0 END) = 0
ORDER BY VIEW_COUNT DESC;

拡張された説明は次のとおりです。

+----+-------------+------------+------+---------------+---------------+---------+-------+--------+----------+----------------------------------------------+
| id | select_type | table      | type | possible_keys | key           | key_len | ref   | rows   | filtered | Extra                                        |
+----+-------------+------------+------+---------------+---------------+---------+-------+--------+----------+----------------------------------------------+
|  1 | SIMPLE      | topsources | ref  | CATEGORY_SLUG | CATEGORY_SLUG | 302     | const | 160790 |   100.00 | Using where; Using temporary; Using filesort |
+----+-------------+------------+------+---------------+----

-----------+---------+-------+--------+----------+ ----------------------------------------------+

このクエリを改善する方法はありますか? また、CPU 負荷の軽減に役立つ mysql 設定はありますか? サーバーで使用可能なメモリをより多く割り当てることができます。

4

4 に答える 4

1

クエリに役立つ可能性が最も高いのは、CATEGORY_SLUG のインデックスです。特に、多くの値を取る場合はそうです。(つまり、クエリが非常に選択的である場合。)クエリは、結果を取得するためにテーブル全体を読み取る必要がありますが、10 秒は長い時間のように思えます。

HAVING 句がクエリ処理に影響を与えるとは思いません。

クエリを 2 回続けて実行すると、同じくらい時間がかかりますか?

于 2012-07-05T18:11:16.560 に答える
0

これを読んだら、それでうまくいくはずです。

SELECT topsources.SOURCE_SLUG, COUNT(topsources.SOURCE_SLUG) AS VIEW_COUNT
FROM topsources
WHERE CATEGORY_SLUG = '/newssource' and 
    topsources.SOURCE_SLUG not in (
        select distinct SOURCE_SLUG 
        from topsources 
        where USER_ID = 'xxxx'
        )
GROUP BY topsources.SOURCE_SLUG
ORDER BY VIEW_COUNT DESC;
于 2012-07-05T18:07:59.027 に答える
0

自分でデータにクエリを投げることができない場合、何かを最適化することは常に困難ですが、自分で行う場合、これが私の最初の試みになります。

SELECT t.SOURCE_SLUG, COUNT(t.SOURCE_SLUG) AS VIEW_COUNT
FROM topsources t
LEFT JOIN (
    SELECT SOURCE_SLUG
    FROM topsources t
    WHERE CATEGORY_SLUG = '/newssource'
    AND USER_ID = 'xxx'
    GROUP BY .SOURCE_SLUG
) x USING (SOURCE_SLUG)
WHERE t.CATEGORY_SLUG = '/newssource'
AND x.SOURCE_SLUG IS NULL
GROUP BY t.SOURCE_SLUG
ORDER BY VIEW_COUNT DESC;
于 2012-07-06T08:23:07.510 に答える
0

CATEGORY_SLUG 基準に一致する行が多数ある場合、これを高速化するのは難しいかもしれませんが、これはより高速ですか?

SELECT ts.SOURCE_SLUG, COUNT(ts.SOURCE_SLUG) AS VIEW_COUNT 
FROM topsources ts
WHERE ts.CATEGORY_SLUG = '/newssource' 
  AND NOT EXISTS(SELECT 1 FROM topsources ts2
                 WHERE ts2.CATEGORY_SLUG = '/newssource'
                   AND ts.SOURCE_SLUG = TS2.SOURCE_SLUG
                   AND ts2.USER_ID = 'xxxx')
GROUP BY ts.SOURCE_SLUG 
ORDER BY VIEW_COUNT DESC;
于 2012-07-05T18:27:24.260 に答える