2010-08-24 4 views
0

Ceci est un exemple complet d'une requête SELECT que j'utilise fréquemment sur l'un de mes sites. Nous avons de très mauvais problèmes avec les temps de chargement de page avec notre hôte, donc j'essaye de faire tout ce que je peux pour optimiser chaque bit de code que le site utilise. Je ne suis pas un expert en ce qui concerne MySQL, alors j'espère que certains d'entre vous pourront vous aider. Voici la requête que je suis en train d'optimiser un peu plus -Aide MySQL Select Optimization?

Select ID, Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15 From table_1 
Where Active = '1' And Col2 LIKE '%Cat%' And Col3 <> 'blah' And Col3 <> 'blah1' And Col3 <> 'blah2' And Col3 <> 'blah3' And Col3 <> 'blah4' And Col3 <> 'blah5' And Col3 <> 'blah6' 
And ID Not In (Select t2ID From table_2 Where table_2.t2ID = table_1.ID And table_2.Col1 = '1' And table_2.Col2 = '1') 
And ID Not In (Select t3ID From table_3 Where table_3.t3ID = table_1.ID And table_3.Col1 = '1') 
And ID Not In (Select t4ID From table_4 Where table_4.t4ID = table_1.ID And table_4.Col1 = '1') 

Fondamentalement, il vérifie 1 table (table_1) et tire toutes les lignes match qui ne se trouvent pas dans table_2, table_3 et TABLE_4. Je suis sûr qu'il existe un moyen beaucoup plus efficace de le faire à part plusieurs sous-sélections. Toute aide est grandement appréciée! Merci d'avance :)

MISE À JOUR: Fondamentalement, tout ce que je suis curieux de savoir est, y at-il quelque chose de plus rapide que les sous-sélections multiples dans la requête? Je suis sûr qu'il existe un moyen d'obtenir les résultats d'une table qui n'existent pas dans plusieurs autres tables qui est beaucoup plus efficace que de faire des sous-sélections ... Le seul point commun entre les tables est que l'ID de table_1, est identique à une autre colonne dans chacune des 3 autres tables (ce que je suis en train de vérifier actuellement en utilisant les sous-sélections). Malheureusement, je ne peux pas comprendre quelle est la façon la plus efficace de faire cette requête ... Merci pour la contribution de tout le monde jusqu'à présent!

TABLEAU AGENCEMENT

mysql> show create table campaigns\G 
*************************** 1. row *************************** 
Table: campaigns 
Create Table: CREATE TABLE `campaigns` ( 
`ID` int(11) NOT NULL auto_increment, 
`CreatedOn` datetime NOT NULL, 
`AddedBy` varchar(75) default NULL, 
`pCampaignName` varchar(255) default NULL, 
`CampaignName` varchar(255) default NULL, 
`CampaignValue` decimal(65,2) default '0.00', 
`CampaignPayout` decimal(65,2) NOT NULL default '0.00', 
`CampaignT` double NOT NULL default '0', 
`CampaignSD` double NOT NULL default '0', 
`ReportingTime` varchar(255) default NULL, 
`CampaignExpiration` varchar(100) default NULL, 
`DurationType` varchar(100) default NULL, 
`Countries` varchar(100) default NULL, 
`CampaignDescription` longtext, 
`CampaignRequirements` longtext, 
`CampaignType` varchar(50) default NULL, 
`CampaignID` varchar(255) default NULL, 
`BannerImageWidth` int(10) NOT NULL default '0', 
`BannerImageHeight` int(10) NOT NULL default '0', 
`BannerImageURL` varchar(255) default NULL, 
`BannerImageAlternateText` varchar(255) default NULL, 
`DisplayBanner` int(1) NOT NULL default '0', 
`CampaignCode` longtext, 
`CampaignURL` longtext, 
`CampaignActive` int(1) NOT NULL default '0', 
`Status` varchar(255) default NULL, 
`Affiliate` varchar(255) default NULL, 
`NewOfferEmailSent` int(1) unsigned NOT NULL default '0', 
`NumberApproved` double(65,2) NOT NULL default '0.00', 
`NumberLeads` double NOT NULL default '0', 
`ThumbsUp` double NOT NULL default '0', 
`ThumbsDown` double NOT NULL default '0', 
`CampaignPoints` double NOT NULL default '0', 
`UserRatingUp` double NOT NULL default '0', 
`UserRatingDown` double NOT NULL default '0', 
PRIMARY KEY (`ID`) 
) ENGINE=MyISAM AUTO_INCREMENT=1608 DEFAULT CHARSET=utf8 
1 row in set (0.09 sec) 

mysql> show indexes from campaigns\G 
*************************** 1. row *************************** 
Table: campaigns 
Non_unique: 0 
Key_name: PRIMARY 
Seq_in_index: 1 
Column_name: ID 
Collation: A 
Cardinality: 1596 
Sub_part: NULL 
Packed: NULL 
Null: 
Index_type: BTREE 
Comment: 
1 row in set (0.10 sec) 

mysql> 
mysql> show create table acampaigns\G 
*************************** 1. row *************************** 
Table: acampaigns 
Create Table: CREATE TABLE `acampaigns` ( 
`ID` int(11) NOT NULL auto_increment, 
`CreatedOn` datetime NOT NULL, 
`CampaignName` varchar(255) default NULL, 
`CampaignRequirements` longtext, 
`CampaignURL` longtext, 
`CampaignValue` decimal(65,2) NOT NULL, 
`CampaignPayout` decimal(65,2) NOT NULL, 
`CampaignReferralCommissionTier1` decimal(65,2) NOT NULL default '0.20', 
`CampaignReferralCommissionTier2` decimal(65,2) NOT NULL default '0.10', 
`CampaignT` double NOT NULL default '0', 
`CampaignSD` double NOT NULL default '0', 
`CampaignType` varchar(255) default NULL, 
`CampaignID` varchar(100) default NULL, 
`CampaignExpiration` varchar(100) default NULL, 
`CampaignReturnStatus` varchar(100) default NULL, 
`CampaignStatus` varchar(255) default NULL, 
`pCampaignID` int(11) NOT NULL, 
`pCampaignName` varchar(255) default NULL, 
`pUserID` int(11) NOT NULL, 
`pUsername` varchar(75) default NULL, 
`pUserIPAddress` varchar(30) default NULL, 
`ApprovedOn` datetime NOT NULL, 
`MarkedDone` int(1) NOT NULL default '0', 
`Notes` longtext, 
`PaidOn` datetime default NULL, 
`cBonus` decimal(65,2) NOT NULL default '0.00', 
`ReversedReason` varchar(255) default NULL, 
`CampaignPoints` double NOT NULL default '0', 
`Affiliate` varchar(255) default NULL, 
`RC1Paid` int(1) unsigned NOT NULL default '0', 
`RC2Paid` int(1) unsigned NOT NULL default '0', 
PRIMARY KEY (`ID`) 
) ENGINE=MyISAM AUTO_INCREMENT=10996 DEFAULT CHARSET=utf8 
1 row in set (0.44 sec) 

mysql> show indexes from acampaigns\G 
*************************** 1. row *************************** 
Table: acampaigns 
Non_unique: 0 
Key_name: PRIMARY 
Seq_in_index: 1 
Column_name: ID 
Collation: A 
Cardinality: 8936 
Sub_part: NULL 
Packed: NULL 
Null: 
Index_type: BTREE 
Comment: 
1 row in set (0.09 sec) 

mysql> 
mysql> show create table bcampaigns\G 
*************************** 1. row *************************** 
Table: bcampaigns 
Create Table: CREATE TABLE `bcampaigns` ( 
`ID` int(11) NOT NULL auto_increment, 
`CreatedOn` datetime NOT NULL, 
`pCampaignID` int(11) NOT NULL, 
`ReportedByUserID` int(11) NOT NULL, 
`Status` varchar(255) default NULL, 
`Notes` longtext, 
PRIMARY KEY (`ID`) 
) ENGINE=MyISAM AUTO_INCREMENT=375 DEFAULT CHARSET=utf8 
1 row in set (0.08 sec) 

mysql> show indexes from bcampaigns\G 
*************************** 1. row *************************** 
Table: bcampaigns 
Non_unique: 0 
Key_name: PRIMARY 
Seq_in_index: 1 
Column_name: ID 
Collation: A 
Cardinality: 0 
Sub_part: NULL 
Packed: NULL 
Null: 
Index_type: BTREE 
Comment: 
1 row in set (0.08 sec) 

mysql> 
mysql> show create table icampaigns\G 
*************************** 1. row *************************** 
Table: icampaigns 
Create Table: CREATE TABLE `icampaigns` ( 
`ID` int(11) NOT NULL auto_increment, 
`CreatedOn` datetime NOT NULL, 
`pCampaignID` int(11) default NULL, 
`IgnoredByUserID` int(11) default NULL, 
PRIMARY KEY (`ID`) 
) ENGINE=MyISAM AUTO_INCREMENT=567 DEFAULT CHARSET=utf8 
1 row in set (0.09 sec) 

mysql> show indexes from icampaigns\G 
*************************** 1. row *************************** 
Table: icampaigns 
Non_unique: 0 
Key_name: PRIMARY 
Seq_in_index: 1 
Column_name: ID 
Collation: A 
Cardinality: 532 
Sub_part: NULL 
Packed: NULL 
Null: 
Index_type: BTREE 
Comment: 
1 row in set (0.40 sec) 

mysql> 
mysql> explain Select ID, CreatedOn, pCampaignName, 
CampaignName, CampaignRequirements, CampaignURL, Countries, 
CampaignPayout, CampaignPoints, CampaignT, CampaignSD, CampaignType, 
ReportingTime, NumberApproved, NumberLeads 
From campaigns 
-> Where CampaignActive = '1' And CampaignType LIKE 'Cat%' 
And CampaignType <> 'DS' And CampaignType <> 'CC' And CampaignType <> 'PC' 
And CampaignType <> 'PC2' And CampaignType <> 'GCC' And CampaignType <> 'G' 
And CampaignType <> 'R' 
-> And ID Not In (Select pCampaignID From acampaigns 
Where campaigns.ID = acampaigns.pCampaignID And MarkedDone = '1' And campaigns.pUserID = '1') 
-> And ID Not In (Select pCampaignID From bcampaigns 
Where bcampaigns.pCampaignID = campaigns.ID And bcampaigns.ReportedByUserID = '1') 
-> And ID Not In (Select pCampaignID From icampaigns 
Where icampaigns.pCampaignID = campaigns.ID And icampaigns.IgnoredByUserID = '1') 

Répondre

0

Avez-vous essayé d'expliquer votre requête. Si vous n'êtes pas familier avec EXPLAIN, il produira un rapport montrant comment la requête est effectuée et en particulier quels index sont utilisés, et peut montrer où un index est souhaitable mais pas présent.

J'ai aussi trouvé dans le passé que NOT IN peut parfois être horriblement lent. Peut-être que réécrire NOT IN comme NOT EXISTS peut accélérer les choses.

NOT EXISTS (SELECT * 
       FROM table_3 
       WHERE table_3.t3ID = table_1.ID AND 
         table_3.Col1 = '1') 
+0

La modification de NOT IN à NOT EXISTS semble être à peu près la même vitesse (pas de différence significative). En outre, j'ai EXPLIQUÉ la requête et il est retourné principalement NULLs. table_1 lit un peu moins de 1 500 lignes, table_2 lit un peu plus de 7 000 lignes, les deux autres tables ont moins de 500 lignes. Tout le reste sauf les noms de tables et le type select sont NULL. J'ai essayé de construire une requête JOIN qui va tirer les mêmes données juste pour voir si ce serait plus rapide, mais ne peut pas sembler en avoir une qui ne renvoie pas d'erreurs, et récupère les mêmes données. Merci pour l'aide jusqu'à présent! – Jay

0

IDFMA

s'il vous plaît afficher les résultats du script suivant afin que nous puissions analyser votre requête en détail. Si vous pouviez aussi coller les résultats, disons http://pastie.org/ ce serait génial aussi.

grâce

show create table table_1\G 
show indexes from table_1\G 

show create table table_2\G 
show indexes from table_2\G 

show create table table_3\G 
show indexes from table_3\G 

show create table table_4\G 
show indexes from table_4\G 

explain 
Select 
ID, Col1, Col2, Col3, Col4, Col5, Col6, Col7, 
Col8, Col9, Col10, Col11, Col12, Col13, Col14, Col15 
From 
table_1 
Where 
Active = '1' And 
Col2 LIKE '%Cat%' And Col3 <> 'blah' And Col3 <> 'blah1' And Col3 <> 'blah2' And Col3 <> 'blah3' And 
Col3 <> 'blah4' And Col3 <> 'blah5' And Col3 <> 'blah6' And 
ID Not In (Select t2ID From table_2 Where table_2.t2ID = table_1.ID And table_2.Col1 = '1' And table_2.Col2 = '1') And 
ID Not In (Select t3ID From table_3 Where table_3.t3ID = table_1.ID And table_3.Col1 = '1') And 
ID Not In (Select t4ID From table_4 Where table_4.t4ID = table_1.ID And table_4.Col1 = '1'); 
+0

Ce code donnait des erreurs pointant vers "show create table table_1 \ G" et "show indexes from table_1 \ G". – Jay

+0

cela pourrait aider http://pento.net/2009/02/27/the-g-modifier-in-the-mysql-command-line-client/ –

+0

Le message principal a été édité avec les résultats que vous avez demandés. – Jay

0

Vous pouvez diviser cette requête unique en plusieurs étapes distinctes et les mettre dans une seule procédure stockée en utilisant des tables temporaires. Cela le rendra plus lisible et fonctionnera probablement plus vite ...

+0

Cette requête sera exécutée des milliers de fois par jour, par des milliers de membres, ce qui explique pourquoi l'optimisation est nécessaire en premier lieu. Je peux me tromper, mais je ne diviserais pas cette requête en utilisant encore plus de ressources sur le serveur de base de données? – Jay