sql >> Database teknologi >  >> RDS >> Mysql

Vælge værdier, der opfylder forskellige betingelser på forskellige rækker?

Ok, jeg blev nedstemt om dette, så jeg besluttede at teste det:

OPRET TABEL brugerrolle (bruger-id INT, rolleid INT, PRIMÆR NØGLE (brugerid, rolleid));OPRET INDEKS PÅ brugerrolle (rolle); 

Kør denne:

\n";mysql_connect('localhost', 'scratch', 'scratch');if (mysql_error()) { echo "Forbindelsesfejl:" . mysql_error() . "\n";}mysql_select_db('scratch');if (mysql_error()) { echo "Vælg DB-fejl:" . mysql_error() . "\n";}$brugere =200000;$count =0;for ($i=1; $i<=$brugere; $i++) { $roles =rand(1, 4); $available =range(1, 5); for ($j=0; $j<$roller; $j++) { $extract =array_splice($available, rand(0, sizeof($available)-1), 1); $id =$ekstrakt[0]; query("INSERT INTO userrole (bruger-id, rolleid) VÆRDIER ($i, $id)"); $count++; }}$stop =microtime(true);$duration =$stop - $start;$insert =$duration / $count;echo "$count brugere tilføjet.\n";echo "Programmet kørte i $duration sekunder.\n ";echo "Indsæt tid $indsæt sekunder.\n";echo "
\n";funktionsforespørgsel($str) { mysql_query($str); if (mysql_error()) { echo "$str:" . mysql_error() . "\n"; }}?>

Output:

499872 brugere tilføjet.Programmet kørte i 56,5513510704 sekunder.Indsæt tid 0,000113131663847 sekunder. 

Det tilføjer 500.000 tilfældige kombinationer af brugerroller, og der er cirka 25.000, der matcher de valgte kriterier.

Første forespørgsel:

SELECT useridFROM userroleWHERE roleid IN (1, 2, 3)GROUP by useridHAVING COUNT(1) =3 

Forespørgselstid:0,312s

SELECT t1.useridFROM userrole t1JOIN userrole t2 ON t1.userid =t2.userid AND t2.roleid =2JOIN userrole t3 ON t2.userid =t3.userid AND t3.roleid =3AND t1

Forespørgselstid:0,016s

Det er rigtigt. Den join-version, jeg foreslog, er tyve gange hurtigere end den samlede version.

Beklager, men jeg gør dette for at leve og arbejde i den virkelige verden, og i den virkelige verden tester vi SQL, og resultaterne taler for sig selv.

Årsagen til dette burde være ret klar. Den samlede forespørgsel skaleres i pris med tabellens størrelse. Hver række behandles, aggregeres og filtreres (eller ej) gennem HAVING klausul. Join-versionen vil (ved hjælp af et indeks) vælge en delmængde af brugerne baseret på en given rolle, derefter kontrollere den delmængde mod den anden rolle og til sidst den delmængde mod den tredje rolle. Hver udvalg (i relationel algebra vilkår) fungerer på en stadig mindre delmængde. Ud fra dette kan du konkludere:

Ydeevnen af ​​join-versionen bliver endnu bedre med en lavere forekomst af matches.

Hvis der kun var 500 brugere (ud af 500.000 eksemplet ovenfor), der havde de tre angivne roller, vil join-versionen blive betydeligt hurtigere. Den samlede version vil ikke (og enhver forbedring af ydeevnen er et resultat af transport af 500 brugere i stedet for 25.000, hvilket joinversionen naturligvis også får).

Jeg var også nysgerrig efter at se, hvordan en rigtig database (dvs. Oracle) ville håndtere dette. Så jeg gentog stort set den samme øvelse på Oracle XE (kører på den samme Windows XP desktop-maskine som MySQL fra det forrige eksempel), og resultaterne er næsten identiske.

Joins ser ud til at være ilde set, men som jeg har demonstreret, kan aggregerede forespørgsler være en størrelsesorden langsommere.

Opdatering: Efter nogle omfattende test , billedet er mere kompliceret, og svaret vil afhænge af dine data, din database og andre faktorer. Moralen i historien er test, test, test.



  1. Hvordan får jeg min, median og max fra min forespørgsel i postgresql?

  2. Påvirker Sql JOIN-ordren ydeevnen?

  3. MySQL match() mod() - rækkefølge efter relevans og kolonne?

  4. Sådan fungerer MID()-funktionen i MySQL