由于高负载重新设计 query/database
Redesign query/database because of high load
我需要有关查询或重新设计数据库的帮助。我不是数据库管理员,也不是 MySQL wiz.
我有以下 tables:
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)展示最合适的 link。我尝试了几个查询但由于服务器仍然过载而失败。它主要发生在 table pop_contor 获得大约 200k 个条目时。 Table links 中有 ~30 行。
第一次尝试是做 select>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
显示了很多 "Copying to tmp table" 状态。
已替换
hours LIKE '%,".date("H").",%' OR hours = 'all'
和
paused = 0
(添加了暂停链接的列)。
负载从 ~4 下降到 ~0.20。我不敢相信 column LIKE %something
会对查询性能产生多大影响。
我需要有关查询或重新设计数据库的帮助。我不是数据库管理员,也不是 MySQL wiz.
我有以下 tables:
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)展示最合适的 link。我尝试了几个查询但由于服务器仍然过载而失败。它主要发生在 table pop_contor 获得大约 200k 个条目时。 Table links 中有 ~30 行。
第一次尝试是做 select>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
显示了很多 "Copying to tmp table" 状态。
已替换
hours LIKE '%,".date("H").",%' OR hours = 'all'
和
paused = 0
(添加了暂停链接的列)。
负载从 ~4 下降到 ~0.20。我不敢相信 column LIKE %something
会对查询性能产生多大影响。