[英]Mysql Query Execution time takes second to result?
我有兩個表有以下結構
-
visitors
表結構 CREATE TABLE IF NOT EXISTS `visitors` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a_id` int(11) DEFAULT NULL,
`visited_by` int(11) DEFAULT '0',
`ip` varchar(30) DEFAULT NULL,
`browser_name` varchar(255) DEFAULT NULL,
`browser_short_name` varchar(20) DEFAULT NULL,
`browser_version` varchar(20) DEFAULT NULL,
`os_platform` varchar(20) DEFAULT NULL,
`visited_time` datetime DEFAULT NULL,
`is_visited` tinyint(4) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM
numbers
表結構 CREATE TABLE IF NOT EXISTS `numbers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
表格訪問者的總記錄為172,153,表格總數記錄為5,896
我正在嘗試使用以下查詢獲取最近30天的記錄
select
x.ts AS timestamp,
COUNT( y.`id`) as no_of_visitors,
DATE( y.`visited_time`) as visited_date,
MONTH( y.`visited_time`) as month_visit,
MONTHNAME( y.`visited_time`) as visit_month_name,
WEEKOFYEAR( y.`visited_time`) as visit_week_no,
YEAR( y.`visited_time`) as year_of_visit
from
(SELECT date(DATE_ADD( CURDATE( ) , INTERVAL CAST(n.id as SIGNED) - 30 DAY)) AS ts
FROM numbers n
WHERE DATE_ADD(CURDATE( ), INTERVAL CAST(n.id as SIGNED) - 30 DAY) <= CURDATE( )) x
LEFT JOIN
visitors y
ON
date(y.`visited_time`) = x.ts
GROUP BY DATE(x.ts)
order by DATE( x.ts) desc
在localhost中執行需要4.7833秒。 我在查詢中做錯了什么? 我如何快速執行查詢? 好心的建議
有兩個考慮因素
DATE(y.visited_time)
= x.ts
如果你真的加快了查詢速度,我建議添加額外的字段來存儲visited_time的DATE部分並使其成為INDEXed。 例如
CREATE TABLE IF NOT EXISTS `visitors` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a_id` int(11) DEFAULT NULL,
`visited_by` int(11) DEFAULT '0',
`ip` varchar(30) DEFAULT NULL,
`browser_name` varchar(255) DEFAULT NULL,
`browser_short_name` varchar(20) DEFAULT NULL,
`browser_version` varchar(20) DEFAULT NULL,
`os_platform` varchar(20) DEFAULT NULL,
`visited_time` datetime DEFAULT NULL,
`visited_time_dt` DATE,
`is_visited` tinyint(4) DEFAULT '0',
INDEX(visited_time_dt),
PRIMARY KEY (`id`)
) ENGINE=MyISAM
然后你的最終查詢如下所示,速度更快(我猜)
SELECT
x.ts AS timestamp,
COUNT( y.`id`) as no_of_visitors,
DATE( y.`visited_time`) as visited_date,
MONTH( y.`visited_time`) as month_visit,
MONTHNAME( y.`visited_time`) as visit_month_name,
WEEKOFYEAR( y.`visited_time`) as visit_week_no,
YEAR( y.`visited_time`) as year_of_visit
FROM
(
SELECT
date(DATE_ADD( CURDATE( ) , INTERVAL CAST(n.id as SIGNED) - 30 DAY)) AS ts
FROM
numbers n
WHERE
DATE_ADD(CURDATE( ), INTERVAL CAST(n.id as SIGNED) - 30 DAY) <= CURDATE( )
) x LEFF JOIN visitors y ON y.`visited_time_dt` = x.ts
GROUP BY y.visited_time_dt
ORDER BY y.visited_time_dt desc
那這個呢? z
表只返回帶有MIN,MAX值的1條記錄。 此MIN / MAX值與visitors.visited_date_dt
SELECT
x.ts AS timestamp,
COUNT( y.`id`) as no_of_visitors,
DATE( y.`visited_time`) as visited_date,
MONTH( y.`visited_time`) as month_visit,
MONTHNAME( y.`visited_time`) as visit_month_name,
WEEKOFYEAR( y.`visited_time`) as visit_week_no,
YEAR( y.`visited_time`) as year_of_visit
FROM numbers n
WHERE
(
SELECT
date(DATE_ADD(CURDATE(), INTERVAL CAST(n.id as SIGNED) - 30 DAY)) AS ts
FROM
numbers n
WHERE
CURDATE() >= DATE_ADD(CURDATE(), INTERVAL CAST(n.id as SIGNED) - 30 DAY
) x
LEFF JOIN visitors y ON y.`visited_time_dt` = x.ts
INNER JOIN
(
SELECT
MAX(DATE_ADD(CURDATE(), INTERVAL CAST(n.id as SIGNED) - 30 DAY)) AS max_ts,
MAX(DATE_ADD(CURDATE(), INTERVAL CAST(n.id as SIGNED) - 30 DAY)) AS min_ts,
FROM
numbers n
WHERE
CURDATE() >= DATE_ADD(CURDATE(), INTERVAL CAST(n.id as SIGNED) - 30 DAY
) z ON y.visited_time_dt BETWEEN z.min_ts AND z.max_ts
GROUP BY y.visited_time_dt
ORDER BY y.visited_time_dt desc
你不只是想要:
select
COUNT( y.`id`) as no_of_visitors,
DATE( y.`visited_time`) as visited_date,
MONTH( y.`visited_time`) as month_visit,
MONTHNAME( y.`visited_time`) as visit_month_name,
WEEKOFYEAR( y.`visited_time`) as visit_week_no,
YEAR( y.`visited_time`) as year_of_visit
from
visitors y
where y.`visited_time` > date_add(curdate(), interval -30 day)
group by DATE(y.`visited_time`)
order by DATE(y.`visited_time`) desc
使用數字表的整個事情會導致一個非常大的連接操作,這是低效的,我認為是不必要的,盡管我真的不明白你在用表號做什么...
編輯:如果你想要所有日期,我會在上述查詢結束后加入:
select * from
all_dates a left join
(select
COUNT( y.`id`) as no_of_visitors,
DATE( y.`visited_time`) as visited_date,
MONTH( y.`visited_time`) as month_visit,
MONTHNAME( y.`visited_time`) as visit_month_name,
WEEKOFYEAR( y.`visited_time`) as visit_week_no,
YEAR( y.`visited_time`) as year_of_visit
from
visitors y
where y.`visited_time` > date_add(curdate(), interval -30 day)
group by DATE(y.`visited_time`)
order by DATE(y.`visited_time`) desc) b
on a.date = b.visited_date;
顯然all_dates是你的日期表。
在visited_time
上創建索引
CREATE INDEX `visited_time_ix` on visitors( `visited_time` );
並嘗試此查詢:
select
x.ts AS timestamp,
COUNT( y.`id`) as no_of_visitors,
DATE( y.`visited_time`) as visited_date,
MONTH( y.`visited_time`) as month_visit,
MONTHNAME( y.`visited_time`) as visit_month_name,
WEEKOFYEAR( y.`visited_time`) as visit_week_no,
YEAR( y.`visited_time`) as year_of_visit
from
(SELECT date(DATE_ADD( CURDATE( ) , INTERVAL CAST(n.id as SIGNED) - 30 DAY)) AS ts
FROM numbers n
WHERE DATE_ADD(CURDATE( ), INTERVAL CAST(n.id as SIGNED) - 30 DAY) <= CURDATE( )) x
LEFT JOIN
visitors y
ON
date(y.`visited_time`) = x.ts
WHERE y.`visited_time` >= ( SELECT min( date(DATE_ADD( CURDATE( ) , INTERVAL CAST(n.id as SIGNED) - 30 DAY)) )
FROM numbers n
WHERE DATE_ADD(CURDATE( ), INTERVAL CAST(n.id as SIGNED) - 30 DAY) <= CURDATE( )
)
AND y.`visited_time` <= ( SELECT max( date(DATE_ADD( CURDATE( ) , INTERVAL CAST(n.id as SIGNED) - 29 DAY)) )
FROM numbers n
WHERE DATE_ADD(CURDATE( ), INTERVAL CAST(n.id as SIGNED) - 30 DAY) <= CURDATE( )
)
GROUP BY DATE(x.ts)
order by DATE( x.ts) desc
;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.