2010-06-29 7 views
0

HI tousPouvez-vous dire quel est le problème avec cette requête?

J'utilise une base de données unique et près de 7 tables. Avez-vous des données remplies avec tous les tableaux. dire près d'environ 10k à partir de maintenant. mais va se développer et peut frapper des millions mais prendra du temps.

Ma question est pourquoi ma requête est lent à récupérer des résultats. il prend environ 10 à 12 secondes pour une requête sur les conditions de non-charge. Je suis inquiet si ce qui se passe dans des conditions de charge dit des milliers de requêtes à la fois ??

voici mon exemple de requête ...

$result = $db->sql_query("SELECT * FROM table1,table2,table3,table4,table5 WHERE table1.url = table2.url AND table1.url = table3.url AND table1.url = table4.url AND table1.url = table5.url AND table1.url='".$uri."'")or die(mysql_error()); 

$row = $db->sql_fetchrow($result); 

$daysA = $row['regtime']; 
$days = (strtotime(date("Y-m-d")) - strtotime($row['regtime']))/(60 * 60 * 24); 
if($row > 0 && $days < 2){ 

$row['data']; 
$row['data1']; 
//remaining 

}else{ //some code} 
+0

les champs d'URL sont-ils indexés? et qu'est-ce que "tfdata.web"? –

+0

@Lasse V. Karlsen .... désolé était une erreur je l'ai corrigé – mathew

+0

et mysql_error est ... – Leo

Répondre

0

Je ne sais pas si vous avez résolu le problème ou non, mais voici quelques données de test que j'ai produites. Un certain nombre de facteurs peuvent affecter la vitesse de vos requêtes. Par conséquent, mes cas de test simples peuvent ne pas refléter correctement vos tables ou vos données. Cependant, ils servent de point de départ utile. D'abord, créez 5 tables simples, chacune avec la même structure. Comme avec vos tables, je l'ai utilisé un indice UNIQUE sur la colonne url:

CREATE TABLE `table1` (
    `id` int(11) NOT NULL auto_increment, 
    `url` varchar(255) default NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `url` (`url`) 
) ENGINE=InnoDB; 

CREATE TABLE table2 LIKE table1; 
CREATE TABLE table3 LIKE table1; 
CREATE TABLE table4 LIKE table1; 
CREATE TABLE table5 LIKE table1; 

Le script suivant crée une procédure stockée qui est utilisée pour remplir chaque table avec 10.000 lignes de données:

DELIMITER // 
DROP PROCEDURE IF EXISTS test.autofill// 
CREATE PROCEDURE test.autofill() 
BEGIN 
    DECLARE i INT DEFAULT 5; 
    WHILE i < 10000 DO 
     INSERT INTO table1 (url) VALUES (CONCAT('wwww.stackoverflow.com/', i)); 
     INSERT INTO table2 (url) VALUES (CONCAT('wwww.stackoverflow.com/', 10000 - i)); 
     INSERT INTO table3 (url) VALUES (CONCAT('wwww.stackoverflow.com/', i + 6000)); 
     INSERT INTO table4 (url) VALUES (CONCAT('wwww.stackoverflow.com/', i + 3000)); 
     INSERT INTO table5 (url) VALUES (CONCAT('wwww.stackoverflow.com/', i + 2000)); 
     SET i = i + 1; 
    END WHILE; 
END; 
// 
DELIMITER ; 

CALL test.autofill(); 

Chaque table contient maintenant 10 000 lignes.Votre déclaration SELECT peut maintenant être utilisé pour interroger les données:

SELECT * 
FROM table1,table2,table3,table4,table5 
WHERE table1.url = table2.url 
AND table1.url = table3.url 
AND table1.url = table4.url 
AND table1.url = table5.url 
AND table1.url = 'wwww.stackoverflow.com/8000'; 

Cela donne le résultat suivant presque instantanément:

+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+ 
| id | url       | id | url       | id | url       | id | url       | id | url       | 
+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+ 
| 7996 | wwww.stackoverflow.com/8000 | 1996 | wwww.stackoverflow.com/8000 | 1996 | wwww.stackoverflow.com/8000 | 4996 | wwww.stackoverflow.com/8000 | 5996 | wwww.stackoverflow.com/8000 | 
+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+------+-----------------------------+ 

Un EXPLAIN SELECT montre pourquoi la requête est très rapide:

EXPLAIN SELECT * 
FROM table1,table2,table3,table4,table5 
WHERE table1.url = table2.url 
AND table1.url = table3.url 
AND table1.url = table4.url 
AND table1.url = table5.url 
AND table1.url = 'wwww.stackoverflow.com/8000'; 

+----+-------------+--------+-------+---------------+------+---------+-------+------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+--------+-------+---------------+------+---------+-------+------+-------------+ 
| 1 | SIMPLE  | table1 | const | url   | url | 258  | const | 1 | Using index | 
| 1 | SIMPLE  | table2 | const | url   | url | 258  | const | 1 | Using index | 
| 1 | SIMPLE  | table3 | const | url   | url | 258  | const | 1 | Using index | 
| 1 | SIMPLE  | table4 | const | url   | url | 258  | const | 1 | Using index | 
| 1 | SIMPLE  | table5 | const | url   | url | 258  | const | 1 | Using index | 
+----+-------------+--------+-------+---------------+------+---------+-------+------+-------------+ 

select_type est SIMPLE, ce qui signifie qu'il n'y a pas JOIN déclarations de ralentir les choses.

type est const, ce qui signifie que la table a au plus un match possible - ce grâce à l'indice UNIQUE, qui garantit pas deux URL sera le même (voir mysql 5.0 indexes - Unique vs Non Unique pour une bonne description de UNIQUE INDEX). Une valeur const dans la colonne type est à peu près aussi bonne que vous pouvez l'obtenir.

possible_keys et key utilisez la clé url. Cela signifie que l'index correct est utilisé pour chaque table.

ref est const, ce qui signifie que MySQL compare une valeur constante (une qui ne change pas) avec l'index. Encore une fois, c'est très rapide.

rows est égal à 1. MySQL n'a besoin que de regarder une ligne de chaque table. Encore une fois, c'est très rapide.

Extra est Using index. MySQL n'a pas à effectuer de recherches supplémentaires non indexées sur les tables.

Si vous avez un index sur la colonne url de chaque table, votre requête devrait être être extrêmement rapide.

+0

Je reçois cette erreur Erreur requête SQL: CREATE PROCEDURE test.autofill ( ) BEGIN DECLARE i INT DEFAULT 5; MySQL a déclaré: Documentation # 1064 - Vous avez une erreur dans votre syntaxe SQL; consultez le manuel qui correspond à votre version du serveur MySQL pour la bonne syntaxe à utiliser près de '' à la ligne 3 – mathew

+0

hey done .... J'ai eu le résultat exact de ce que vous avez montré ... est-ce que ça veut dire que tout va bien? bien alors j'ai besoin de changer toute la structure de ma table .... mais si c'est rapide alors je suis très heureux – mathew

+0

@mathew: Erreur 1064 se réfère à l'utilisation d'un [mot réservé] (http: //dev.mysql .com/doc/refman/5.0/fr/reserved-words.html). Quelle version de MySQL utilisez-vous? Avez-vous copié et collé la fonction telle quelle, avec les instructions 'DELIMITER'? – Mike

0

Il semble probable que certaines des colonnes de votre WHERE clause ne sont pas indexed. Les index sont utilisés pour rechercher rapidement des lignes avec des valeurs de colonne spécifiques. Sans un index, MySQL doit commencer par la première ligne, puis lire toute la table pour trouver les lignes pertinentes.

Vous trouverez peut-être EXPLAIN utile dans l'analyse de vos requêtes.

+0

J'ai fait Indexation pour toutes les tables sur la colonne 'url' et j'ai interrogé EXPLAIN et cela retourne la structure entière de la table ... mais qu'est-ce que j'ai besoin de comprendre? – mathew

+0

oh J'ai ajouté UNIQUE INDEX pour la colonne url. parce que je ne veux pas de répétition ... est-ce que cela peut interférer? – mathew

+0

UNIQUE INDEX est un index. En ce qui concerne la compréhension EXPLIQUER, consultez http://www.databasejournal.com/features/mysql/article.php/1382791/Optimizing-MySQL-Queries-and-Indexes.htm –

0

ressemble vraiment à un index sur le champ url dans chaque tableau est le chemin à parcourir

0

Look Up et regarder en particulier les JOIN sont à la différence entre des inner join, GAUCHE REJOINT et Jointures externes. INDEX également tous les champs sur lesquels vous allez faire une recherche.

0

Probablement un problème avec vos index!

Dans tous les cas, les longues chaînes de caractères comme les URLs rendent les clés primaires peu performantes. La prise de place dans l'index est importante et les index ne sont pas aussi denses qu'ils pourraient l'être et moins de pointeurs de lignes sont chargés par IO. Aussi avec des urls les chances sont que 99% de vos chaînes commencent par "http://www". Le moteur de base de données doit donc comparer 13 caractères avant de décider qu'une ligne ne correspond pas. Une solution consiste à utiliser une fonction de hachage telle que MD5, SHA1 ou même CRC32 pour obtenir une valeur binaire brute de vos chaînes et utiliser cette valeur comme clé primaire pour vos tables. CRC32 fait une belle clé primaire de taille entière mais il est quasiment certain qu'à un certain moment vous rencontrerez deux URLs qui ont la même valeur CRC32 donc vous devrez stocker et comparer la chaîne "url" pour être sûr. Les autres fonctions de hachage retournent des valeurs plus longues (16 octets et 20 octets respectivement en mode "brut") mais les chances d'une collision sont si faibles que cela ne vaut pas la peine de s'en soucier.

.

+0

fait http: // www. est coupé avant qu'il ne va à la base de données – mathew

+1

@mathew c'est une erreur de dépouiller le www. Par exemple, www.somedomain.com n'est pas la même chose que somedomain.com. Oui, de nos jours, la plupart des sites Web ont leurs entrées DNS pointant vers le même serveur Web, mais ce n'est qu'une convention. Quoi qu'il en soit, dépouiller 3 caractères d'une URL ne va pas raccourcir de beaucoup la plupart des URL. –

Questions connexes