Hvilket ikke virker optimalt. Jeg har forsøgt at gennemgå MySQL's 'Optimizing with EXPLAIN' og deres 'Optimizing with JOIN' grundigt, men jeg synes ikke at gøre mig klogere.
Her er mit query:
SELECT `a`.`ad_id`, COUNT(DISTINCT `kwhere`.`keyword_id`), COUNT(DISTINCT `kwho`.`keyword_id`) FROM `test_ads` as `a`
LEFT JOIN `test_ad_keys_where` `where` ON `where`.`ad_id`=`a`.`ad_id`
LEFT JOIN `test_ad_keys_who` `who` ON `who`.`ad_id`=`a`.`ad_id`
LEFT JOIN `test_keywords` `kwhere` ON `kwhere`.`keyword_id`=`where`.`keyword_id` AND `kwhere`.`keyword` LIKE 'køb%'
LEFT JOIN `test_keywords` `kwho` ON `kwho`.`keyword_id`=`who`.`keyword_id` AND `kwho`.`keyword` LIKE 'invest%'
GROUP BY `a`.`ad_id`
HAVING COUNT(DISTINCT `kwhere`.`keyword_id`) > 0 AND COUNT(DISTINCT `kwho`.`keyword_id`) > 0
En kort forklaring: De to 'test_ad_keys_*' tabeller indeholder relationer mellem keywords og ads.
Struktur for ads tabellen:
CREATE TABLE `test_ads` ( `ad_id` int(11) NOT NULL auto_increment, `customer_id` int(11) NOT NULL default '0', `order_id` int(11) NOT NULL default '0', `type` tinyint(4) NOT NULL default '0', `link_id` int(11) NOT NULL default '0', PRIMARY KEY (`ad_id`), KEY `customer_id` (`customer_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_danish_ci;
Bare et forslag (jeg aner ærligt talt ikke om det ændrer noget):
Da HAVING tester på, om der er nogle 'keyword_id' og disse er sammenknytningskriteriet, burde du kunne filtrere allerede på et tidligere tidspunkt, altså før grupperingen ved at ændre til en INNER JOIN. Disse Id felter vil jo kun være tælbare hvis de ikke er null. Da begge tællere skal være > 0 er der for mig at se ingen grund til at bruge LEFT JOINs og gruppere på en masse rækker, som alligevel senere bliver filtreret fra i HAVING segmentet.
Mit utestede forslag ville derfor være:
SELECT `a`.`ad_id`, COUNT(DISTINCT `kwhere`.`keyword_id`), COUNT(DISTINCT `kwho`.`keyword_id`) FROM `test_ads` as `a`
INNER JOIN `test_ad_keys_where` `where` ON `where`.`ad_id`=`a`.`ad_id`
INNER JOIN `test_ad_keys_who` `who` ON `who`.`ad_id`=`a`.`ad_id`
INNER JOIN `test_keywords` `kwhere` ON `kwhere`.`keyword_id`=`where`.`keyword_id` AND `kwhere`.`keyword` LIKE 'køb%'
INNER JOIN `test_keywords` `kwho` ON `kwho`.`keyword_id`=`who`.`keyword_id` AND `kwho`.`keyword` LIKE 'invest%'
GROUP BY `a`.`ad_id`
Det er som sagt rent "hjernespin", så måske er jeg helt forkert på den, og så kan du jo bare ignorere mit indfald.
Det var ihvertfald en væsentlig optimering :-) Men jeg er nu stadig ikke tilfreds. Jeg har for mange records til at det er hurtigt nok. EXPLAIN afslører med mit eget query en gennemsøgning af 6.050.000 records, mod 5.300.000 med dit.
Kan du foreslå en yderligere forbedring?
Det jeg selv ser som en mulighed, jeg ikke ved om har nogen reel værdi, er at undlade at joine ads tabellen i starten. Dvs. lave et subquery, som henter ad_ids, hvorefter jeg joiner dette subquery som en derived table med ads tabellen.
Det er i øvrigt ikke nødvendigt med denne COUNT i SELECT. Den brugte jeg i mit eget query til at se om der var nogle resultater. Din løsning er i dette tilfælde MEGET bedre!
En anden idé jeg har, er at omrokere queriet, så ads-tabellen ikke er den som står efter FROM. Den tabel jeg forventer mindst rækker fra, hvorfor jeg vil mene at den er den bedste at gå ud fra, er kwhere og kwho. Men da der er to, kan jeg simpelthen ikke gennemskue hvordan og hvorledes.
Håber at du, eller en anden, kan hjælpe :-)
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.