由于高负载重新设计查询/数据库
Posted
技术标签:
【中文标题】由于高负载重新设计查询/数据库【英文标题】:Redesign query/database because of high load 【发布时间】:2017-10-29 17:34:31 【问题描述】:我在查询或重新设计我的数据库方面需要帮助。我不是数据库管理员,也不是 mysql 专家。
我有以下表格:
CREATE TABLE IF NOT EXISTS `pop_contor` (
`key` varchar(50) NOT NULL,
`uniqueHandler` varchar(30) DEFAULT NULL,
`uniqueLink` varchar(30) DEFAULT NULL,
`uniqueUser` varchar(30) DEFAULT NULL,
`owner` varchar(50) NOT NULL,
`ip` varchar(15) DEFAULT NULL,
`page` varchar(500) DEFAULT NULL,
`share` float DEFAULT NULL,
`cadv` float NOT NULL,
`os` varchar(50) NOT NULL,
`browsershort` varchar(50) NOT NULL,
`browser` varchar(50) DEFAULT NULL,
`country` varchar(10) DEFAULT NULL,
`date` date DEFAULT NULL,
`hour` int(2) NOT NULL,
`tstamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`key`),
KEY `contor_IX1` (`uniqueLink`,`ip`),
KEY `owner` (`owner`,`share`,`hour`),
KEY `uniqueUser` (`uniqueUser`,`share`,`hour`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
和:
CREATE TABLE IF NOT EXISTS `pop_links` (
`unique` varchar(8) NOT NULL DEFAULT '',
`uniqueUser` varchar(30) DEFAULT NULL,
`uniqueCategories` varchar(150) DEFAULT NULL,
`browser` varchar(60) NOT NULL,
`os` varchar(50) NOT NULL,
`country` varchar(100) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`url` varchar(500) CHARACTER SET ascii DEFAULT NULL,
`description` varchar(150) DEFAULT NULL,
`bid` varchar(6) DEFAULT NULL,
`amount` varchar(5) DEFAULT NULL,
`remain` varchar(20) DEFAULT NULL,
`rtoday` varchar(20) NOT NULL DEFAULT '0',
`frequency` varchar(2) DEFAULT NULL,
`dlimit` varchar(6) NOT NULL DEFAULT '0',
`hours` varchar(100) NOT NULL DEFAULT 'all',
`block` varchar(500) CHARACTER SET ascii NOT NULL,
`valid` int(1) DEFAULT NULL,
`payed` int(1) DEFAULT NULL,
`startDate` date DEFAULT NULL,
`endDate` date DEFAULT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`unique`),
KEY `unique` (`unique`,`uniqueCategories`,`browser`,`os`,`country`,`url`,`bid`,`remain`,`rtoday`,`frequency`,`hours`,`block`,`valid`,`startDate`,`endDate`,`uniqueUser` )
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我要做的是根据几个标准向每个访问者(基于 ip)显示最适合的链接。我尝试了几个查询,但由于服务器仍然超载而失败。它主要发生在表 pop_contor 获得大约 200k 个条目时。表格链接中有大约 30 行。
第一次尝试是选择>where>select>where>select>where,但它吃了我的午餐,包括我的午餐盒。
第二次尝试是(查询大约需要 5 秒才能完成):
SELECT l. * FROM pop_links AS l
LEFT JOIN ( SELECT uniqueLink, SUM( ip = '".$ip."' ) AS ip_visits
FROM pop_contor
GROUP BY uniqueLink ) AS c
ON c.uniqueLink = l.unique AND ip_visits <= frequency
WHERE (`uniqueCategories` LIKE '%,".$cat.",%'OR `uniqueCategories` = '1')
AND (`hours` LIKE '%,".date("H").",%' OR `hours` = 'all')
AND (`browser` LIKE '%".$user_browser[name]."%' OR `browser` = '1')
AND (`country` LIKE '%".$ccode."%' OR `country` = '1')
AND (`os` LIKE '%".$user_browser[platform]."%' OR `os` = '1')
AND (`remain` > '0')
AND (`rtoday` > '0')
AND `valid` = '1'
AND (`block` NOT LIKE '%".$unique."%')
ORDER BY `bid` DESC, `remain` DESC
LIMIT 1
解释:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY l ALL NULL NULL NULL NULL 16 Using where; Using temporary; Using filesort
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 16
2 DERIVED pop_contor index NULL contor_IX1 141 NULL 299128 Using index
第三次尝试:
SELECT pop_links.unique, pop_links.uniqueUser, pop_links.uniqueCategories, pop_links.browser, pop_links.os, pop_links.country, pop_links.url, pop_links.bid, pop_links.remain, pop_links.rtoday, pop_links.frequency, pop_links.hours, pop_links.block, pop_links.valid, pop_links.startDate, pop_links.endDate, COUNT( IF( pop_contor.ip = '".$ip."', 1, NULL ) ) < pop_links.frequency AS toto
FROM pop_links
LEFT JOIN pop_contor
ON pop_links.unique = pop_contor.uniqueLink
WHERE (`uniqueCategories` LIKE '%,".$cat.",%' OR `uniqueCategories` = '1')
AND (`hours` LIKE '%,".date("H").",%' OR `hours` = 'all')
AND (pop_links.browser LIKE '%".$user_browser[name]."%' OR pop_links.browser = '1')
AND (pop_links.country LIKE '%".$ccode."%' OR pop_links.country = '1')
AND (pop_links.os LIKE '%".$user_browser[platform]."%' OR pop_links.os = '1')
AND (`remain` > '0')
AND `rtoday` > '0'
AND `valid` = '1'
AND (`block` NOT LIKE '%".$unique."%')
GROUP BY pop_links.unique, pop_contor.uniqueLink
ORDER BY `toto` DESC , pop_links.bid DESC , pop_links.remain DESC
LIMIT 1
解释:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE pop_links index NULL unique 2683 NULL 16 Using where; Using index; Using temporary; Using f...
1 SIMPLE pop_contor ref contor_IX1 contor_IX1 93 admin_pops.pop_links.unique 13277 Using index
查询在大约 0.3 秒内完成,但服务器上的负载仍然很高。 SHOW PROCESSLIST
向我展示了很多“复制到 tmp 表”状态。
【问题讨论】:
发布到dba.stackexchange.com 和Check this out 谢谢@AbdullaNilam 在 dba.stack 上我得到“您每 40 分钟只能发帖一次。” 您有许多类似于column LIKE '%something'
的WHERE
过滤条件。这种情况是臭名昭著的 SQL 性能反模式。用更好的 MySQL 索引来优化是不可能的。您没有在问题中解释您的数据是什么样的,因此很难就如何将column LIKE '%something'
重构为column = 'something'
或column LIKE 'something%'
(尾随%
)提出建议。但这就是您必须做的,以使这项工作更有效。
这是pop_links imgur.com/lZpFne4中的数据屏幕
在短期内,删除您为用户提供的搜索选项之一可能是值得的,以减少字符串开头带有通配符的LIKE
子句的数量.也许仅仅删除其中一个过滤器就可以将您的性能提高到可接受的水平?
【参考方案1】:
已更换
hours LIKE '%,".date("H").",%' OR hours = 'all'
和
paused = 0
(在链接中添加了一个暂停的列)。
负载从 ~4 下降到 ~0.20。我无法相信column LIKE %something
会对查询性能产生多大影响。
【讨论】:
以上是关于由于高负载重新设计查询/数据库的主要内容,如果未能解决你的问题,请参考以下文章
java架构师大型分布式综合项目实战,高并发,集群,高可用,程序设计,性能优化,架构设计,负载均衡,大数据量
大型网站的架构设计问题----大型高并发高负载网站的系统架构