나는 매우 단순해야하는 쿼리를 가지고 있지만 많은 두통을 유발합니다. 몇 가지 변수에 따라 광고를 필터링해야하는 간단한 광고 시스템이 있습니다. 일일 조회수/클릭 수 및 특정 광고에 대한 총 조회수/클릭 수를 제한해야합니다. 또한 각 광고는 광고가 게재 될 수있는 하나 이상의 슬롯에 연결됩니다. 각 광고에 대해 필요한 통계를 저장하는 표가 있습니다. 통계표는 매우 자주 변경됩니다. 이 내가 사용하고 테이블입니다 : 이것은 주어진 슬롯 (주 광고를 얻기 위해 사용하는 쿼리가SQL : 다중 조인 쿼리 리팩토링
이CREATE TABLE `t_ads` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
`content` text NOT NULL,
`is_active` tinyint(1) unsigned NOT NULL,
`start_date` date NOT NULL,
`end_date` date NOT NULL,
`max_views` int(10) unsigned NOT NULL,
`type` tinyint(3) unsigned NOT NULL default '0',
`refresh` smallint(5) unsigned NOT NULL default '0',
`max_clicks` int(10) unsigned NOT NULL,
`max_daily_clicks` int(10) unsigned NOT NULL,
`max_daily_views` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `t_ad_slots` (
`id` int(10) unsigned NOT NULL auto_increment ,
`name` varchar(255) NOT NULL,
`width` int(10) unsigned NOT NULL,
`height` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `t_ads_to_slots` (
`ad_id` int(10) unsigned NOT NULL,
`slot_id` int(10) unsigned NOT NULL,
`value` int(10) unsigned NOT NULL,
PRIMARY KEY (`ad_id`,`slot_id`),
KEY `slot_id` (`slot_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `t_ads_to_slots`
ADD CONSTRAINT `t_ads_to_slots_ibfk_1` FOREIGN KEY (`ad_id`) REFERENCES `t_ads` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
ADD CONSTRAINT `t_ads_to_slots_ibfk_2` FOREIGN KEY (`slot_id`) REFERENCES `t_ad_slots` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION;
CREATE TABLE `t_ad_stats` (
`ad_id` int(10) unsigned NOT NULL,
`slot_id` int(10) unsigned NOT NULL,
`date` date NOT NULL COMMENT,
`views` int(10) unsigned NOT NULL,
`unique_views` int(10) unsigned NOT NULL,
`clicks` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`ad_id`,`slot_id`,`date`),
KEY `slot_id` (`slot_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `t_ad_stats`
ADD CONSTRAINT `t_ad_stats_ibfk_1` FOREIGN KEY (`ad_id`) REFERENCES `t_ads` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
ADD CONSTRAINT `t_ad_stats_ibfk_2` FOREIGN KEY (`slot_id`) REFERENCES `t_ad_slots` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION;
이 예에서 열심히 슬롯 ID와 0,1로 (20)를 코딩 2는 광고 유형으로, 나는
SELECT `ads`.`content`, `slots`.`value`, `ads`.`id`, `ads`.`refresh`, `ads`.`type`,
SUM(`total_stats`.`views`) AS "total_views",
SUM(`total_stats`.`clicks`) AS "total_clicks"
FROM (`t_ads` AS `ads`,
`t_ads_to_slots` AS `slots`)
LEFT JOIN `t_ad_stats` AS `total_stats`
ON `total_stats`.`ad_id` = `ads`.`id`
LEFT JOIN `t_ad_stats` AS `daily_stats`
ON (`daily_stats`.`ad_id` = `ads`.`id`) AND
(`daily_stats`.`date` = CURDATE())
WHERE (`ads`.`id` = `slots`.`ad_id`) AND
(`ads`.`type` IN(0,1,2)) AND
(`slots`.`slot_id` = 20) AND
(`ads`.`is_active` = 1) AND
(`ads`.`end_date` >= NOW()) AND
(`ads`.`start_date` <= NOW()) AND
((`ads`.`max_views` = 0) OR
(`ads`.`max_views` > "total_views")) AND
((`ads`.`max_clicks` = 0) OR
(`ads`.`max_clicks` > "total_clicks")) AND
((`ads`.`max_daily_clicks` = 0) OR
(`ads`.`max_daily_clicks` > IFNULL(`daily_stats`.`clicks`,0))) AND
((`ads`.`max_daily_views` = 0) OR
(`ads`.`max_daily_views` > IFNULL(`daily_stats`.`views`,0)))
GROUP BY (`ads`.`id`)
나는이 쿼리 심지어는 아주 긴하지만, 자명하다고 생각)이 쿼리를 호출하는 PHP 스크립트에서이 데이터를 얻을. 내가 사용하고있는 MySQL 버전은 5.0.51a-community입니다. 나에게 큰 문제는 통계 테이블에 대한 이중 조인 (여기서는 특정 레코드와 여러 레코드 (합계)에서 데이터를 가져올 수 있도록하는 것임)입니다.
더 나은 결과를 얻기 위해 어떻게이 쿼리를 구현 하시겠습니까? (InnoDB에서 변경할 수 없다는 점에 유의하십시오.)
내 질문에 대해 분명히 모든 것이 명확하지만, 사실이 아니라면 질문하고 명확히 할 것입니다.
t_ads.is_active
t_ads.start_date
t_ads.end_date
변경에 t_ad_stats에 기본 키의 순서 : 미리 감사합니다, Kfir
두통의 원인은 무엇입니까? 나는 성과를 취할 것이지만 ... 분명히하십시오. –
ANSI-86 및 ANSI-92 스타일 조인을 혼합 할 때 SQL을 읽기가 어렵습니다. '(ads.id = slots.ad_id)'를 내부 결합으로 만들 수도 있습니다. –
이 쿼리를 실행하려고하면 실제로 오류가 발생합니다. GROUP BY는 ads.id를 나열하지만 SELECT는 4 개의 추가 집계되지 않은 필드를 나열합니다. –