需要帮助调整 sql 查询

Posted

技术标签:

【中文标题】需要帮助调整 sql 查询【英文标题】:Need help tuning sql query 【发布时间】:2012-07-05 18:00:29 【问题描述】:

我的 mysql 数据库在尝试执行特别慢的查询时变得很耗 CPU。当我解释时,mysql说“使用where;使用临时;使用文件排序”。请帮助破译和解决这个难题。

表结构:

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 |
+----+-------------+------------+------+---------------+----

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

有没有办法改进这个查询?另外,是否有任何 mysql 设置可以帮助减少 CPU 负载?我可以分配更多可用的内存在我的服务器上。

【问题讨论】:

HAVING MAX(CASE WHEN topsources.USER_ID = 'xxxx' THEN 1 ELSE 0 END) = 0 这部分是我认为最有问题的让我思考如何更好地做到这一点 发布说明的确切输出会有所帮助 在您运行查询时是否发生了更新? 表格的更新一直在发生。 出了点问题:您的 PRIMARY KEY 定义引用了不存在的列:DATE_AND_HOURITEM_ID 【参考方案1】:

最有可能帮助查询的是 CATEGORY_SLUG 上的索引,尤其是当它包含许多值时。 (也就是说,如果查询是高度选择性的。)查询需要读取整个表才能获得结果——尽管 10 秒似乎很长。

我认为 HAVING 子句不会影响查询处理。

如果您连续运行两次查询是否需要同样长的时间?

【讨论】:

CATEGORY_SLUG 上已有索引。请阅读上面的表格结构。查询几乎总是需要更长的时间来运行。 嗯,有多少个分类蛞蝓?有时,索引弊大于利,尤其是在只有少数几个值的情况下。 少于 100 个类别 slug。 尝试运行忽略索引的查询,使用 IGNORE INDEX 提示 (dev.mysql.com/doc/refman/5.1/en/index-hints.html)。使用索引可能会导致页面读取效率低下(随机和多次)。 使用 iGNORE INDEX 提示运行查询。没有帮助。【参考方案2】:

如果有很多行符合您的 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;

【讨论】:

查询返回'where子句'中的未知列'TS2.SOURCE_SLUG' 删除他的行AND ts.SOURCE_SLUG = TS2.SOURCE_SLUG 如果我删除该行,则此查询返回空结果集【参考方案3】:

如果我正确阅读了我的 sql 更改,那应该可以解决问题

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;

【讨论】:

此查询返回不同的结果集。与原始查询不同。 更新了查询试试看【参考方案4】:

当你不能自己对数据进行查询时,总是很难优化某些东西,但如果我自己做这将是我的第一次尝试:

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;

【讨论】:

以上是关于需要帮助调整 sql 查询的主要内容,如果未能解决你的问题,请参考以下文章

sql 这个查询需要一些调整,但基本上,将拉动智能路由的调用,并查看何时调用智能路由

在获取 sql 查询时需要帮助 [关闭]

帮助 SQL 查询 - 需要一些魔法

需要关于 Sql 递归查询的帮助

在构建 SQL 查询方面需要帮助

需要优化SQL查询的帮助