副问题[/!--empirenews.page--]
我有一个查询,用于我们的陈诉体系,偶然运行速率高出一秒,其他时刻必要1到10分钟才气运行.
这是慢查询日记中的条目:
# Query_time: 543 Lock_time: 0 Rows_sent: 0 Rows_examined: 124948974
use statsdb;
SELECT count(distinct Visits.visitorid) as 'uniques'
FROM Visits,Visitors
WHERE Visits.visitorid=Visitors.visitorid
and candidateid in (32)
and visittime>=1275721200 and visittime<=1275807599
and (omit=0 or omit>=1275807599)
AND Visitors.segmentid=9
AND Visits.visitorid NOT IN
(SELECT Visits.visitorid
FROM Visits,Visitors
WHERE Visits.visitorid=Visitors.visitorid
and candidateid in (32)
and visittime<1275721200
and (omit=0 or omit>=1275807599)
AND Visitors.segmentid=9);
它根基上是计较奇异的会见者,它通过计较本日的会见者然后减去之前会见过的会见者来做到这一点.假如您知道更好的要领,请汇报我.
我只是不大白为什么偶然它会这么快,而其他时刻必要这么长时刻 – 纵然在沟通的处事器负载下具有沟通简直切查询.
这是关于此查询的EXPLAIN.正如您所看到的那样,它行使我配置的索引:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY Visits range visittime_visitorid,visitorid visittime_visitorid 4 NULL 82500 Using where; Using index
1 PRIMARY Visitors eq_ref PRIMARY,cand_visitor_omit PRIMARY 8 statsdb.Visits.visitorid 1 Using where
2 DEPENDENT SUBQUERY Visits ref visittime_visitorid,visitorid visitorid 8 func 1 Using where
2 DEPENDENT SUBQUERY Visitors eq_ref PRIMARY,cand_visitor_omit PRIMARY 8 statsdb.Visits.visitorid 1 Using where
几个礼拜前我实行优化查询,并提出了一向一连约2秒的变体,但现实上它花了更多的时刻,由于90%的旧查询返回得更快.每个查询两秒钟太长,由于我们每个页面加载挪用查询最多50次,具有差异的时刻段.
快速举动也许是因为查询生涯在查询缓存中吗?我实行在我的基准测试之间运行’RESET QUERY CACHE’和’FLUSH TABLES’,我大部门时刻如故获得快速的功效.
留意:昨晚运行查询时呈现错误:无法生涯功效集.我最初的研究表白,也许是因为必要修复的糜烂表.这也许是我所看到的举动的缘故起因吗?
假如您必要处事器信息:
>通过PHP 4.4.4 MySQL 4.1.22会见 >全部表都是InnoDB >我们每周在全部表格上运行优化表 >查询中行使的两个表的总和为500 MB
MySQL设置:
key_buffer = 350M
max_allowed_packet = 16M
thread_stack = 128K
sort_buffer = 14M
read_buffer = 1M
bulk_insert_buffer_size = 400M
set-variable = max_connections=150
query_cache_limit = 1048576
query_cache_size = 50777216
query_cache_type = 1
tmp_table_size = 203554432
table_cache = 120
thread_cache_size = 4
wait_timeout = 28800
skip-external-locking
innodb_file_per_table
innodb_buffer_pool_size = 3512M
innodb_log_file_size=100M
innodb_log_buffer_size=4M
这是布局,比尔:
CREATE TABLE `Visitors` (
`visitorid` bigint(20) unsigned NOT NULL auto_increment,`ip` int(11) unsigned default '0',`candidateid` int(11) unsigned NOT NULL default '0',`omit` int(11) unsigned NOT NULL default '0',`segmentid` int(10) unsigned NOT NULL default '0',PRIMARY KEY (`visitorid`),KEY `cand_visitor_omit` (`candidateid`,`visitorid`,`omit`),KEY `ip_omit` (`ip`,`omit`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2837988 ;
CREATE TABLE `Visits` (
`visitid` bigint(20) unsigned NOT NULL auto_increment,`visitorid` bigint(20) unsigned NOT NULL default '0',`visittime` int(11) unsigned NOT NULL default '0',`converted` tinyint(4) NOT NULL default '0',`superconverted` tinyint(4) NOT NULL default '0',`clickedotheroffer` tinyint(4) NOT NULL default '0',PRIMARY KEY (`visitid`),KEY `visittime_visitorid` (`visittime`,`visitorid`),KEY `visitorid` (`visitorid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3912081 ;
最佳谜底
@OMG Ponies的谜底与我在扣问您的表格界说时的设法很是靠近.根基上,在此查询中只必要一个会见者实例.
假如某个会见者在该时刻段内有一些匹配的会见次数,而且没有与该时刻段之前的匹配会见次数,则应计较在
SELECT COUNT(DISTINCT v.visitorid) AS unique_visitor_count
FROM Visitors v
JOIN Visits current ON v.visitorid = current.visitorid
AND current.visittime BETWEEN 1275721200 AND 1275807599
LEFT JOIN Visits earlier ON v.visitorid = earlier.visitorid
AND earlier.visittime < 1275721200
WHERE v.candidateid IN (32)
AND v.segmentid = 9
AND v.omit NOT BETWEEN 1 AND 1275807598
AND earlier.visitorid IS NULL;
您也许会受益于会见者的索引(candidateid,segmentid,omit),由于这些列在WHERE子句中行使.您还可以实行会见者的会见者(visitorid,candidateid,omit).
根基上,假如您可以行使索引来举办查询优化,则意味着它从索引数据布局中获取所需的全部数据,而且基础不必读取表数据!
我实行了屡次索引,实行了上面的查询.我上面提议的索引没有辅佐,它如故但愿行使访客的cand_visitor_omit索引.但我通过反转列变动了会见时的visittime_visitorid索引:
CREATE INDEX visitorid_visittime ON Visits(visitorid,visittime);
这获得了优化打算,汇报我它将行使它作为两个会见毗连的包围索引(请参阅右侧特殊字段中的“行使索引”):
(编辑:湖南网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|