Raketensilo: Input benötigt

Beitrag lesen

Hm. Dann mach ich mal eine vergleichsfähige Gegenprobe

<?php

$w1000 = explode( ' ', file_get_contents( '1000.txt' ) );

$startT = hrtime( true );

$w500 = json_decode( file_get_contents( '500.json' ) );

$helper = [];
foreach ( $w500 as $k ) {
	$helper[ $k ] = true;
}

echo "Lesen der 500 Wörter  : " . ( hrtime( true ) - $startT ) / 1e+6 . " ms.\n";

$startT = hrtime( true );

$founds=[];
foreach ( $w1000 as $w ) {
	if ( array_key_exists ( $w, $helper ) ) {
		$founds[] = $w;
	}
}

echo "Vergleich mit aus 1000: " . ( hrtime( true ) - $startT ) / 1e+6 . " ms.\n\n";

#print_r( $founds );
php 2.php
Lesen der 500 Wörter  : 0.133038 ms.
Vergleich mit aus 1000: 0.119373 ms.

Da sah mit dem antiken microtime(true) nicht anders aus.

Ein bulk-insert ist eigentlich einfach:

INSERT INTO `tabelle` (`Kategorien`)'
VALUES
 ("Wert"),
 ("anderer Wert")
;

Für meine Vergleichsdaten mach ich das so:

<?PHP
# create table `test`.`kategorien` (`Kategorie` VARCHAR(30) NOT NULL );

$w500 = json_decode( file_get_contents( '500.json' ) );

include 'settings.php';
$dbh = new PDO(
  "mysql:host=localhost;dbname=$database",
   $user,
   $pass
);
$dbh -> query( 'DELETE FROM `kategorien`' );

for($i=0; $i<count( $w500 ); $i++) {
	$w500[$i] = '(' . $dbh->quote( $w500[$i] ) . ')';
}

$sql = "INSERT INTO `test`.`kategorien`(`Kategorie`)
  VALUES " . implode(',', $w500 ) .';';

$startT = hrtime( true );
$dbh -> query( $sql );
echo "Einlesen der 500 Wörter in die Datentabelle: " 
   . ( hrtime( true ) - $startT ) / 1e+6 
   . " ms.\n";

Resultat:

Einlesen der 500 Wörter als Bulk-Insert in die Datentabelle: 7.429675 ms

(Diese Zahl interessiert nicht - aber das ist nicht mehr "ewig" 😀)

Kommen wir zur Abfrage:

<?php
# Tabelle angelegt mit:
# create table `test`.`kategorien`
# (`Kategorie` VARCHAR(30) NOT NULL );


# set $database, $user and $pass
include 'settings.php'; 
$dbh = new PDO( 
	"mysql:host=localhost;dbname=$database",
	$user,
	$pass
);

# Frisch einlesen?
/*
$dbh -> query( 'DELETE FROM `kategorien`' );

$w500 = json_decode(
   file_get_contents( '500.json' )
);

for($i=0; $i<count( $w500 ); $i++) {
	$w500[$i] = '(' . $dbh->quote( $w500[$i] ) . ')';
}

$sql = "INSERT INTO `test`.`kategorien`(`Kategorie`) VALUES "
. implode(',', $w500 );

$startT = hrtime( true );
$dbh -> query( $sql );
echo "Einlesen der 500 Wörter in die Datentabelle:       "
. ( hrtime( true ) - $startT ) / 1e+6 . " ms.\n";
#*/

$startT = hrtime( true );
$w1000 = explode( ' ', file_get_contents( '1000.txt' ) );
for($i=0; $i<count( $w1000 ); $i++) {
	$w1000[$i] = $dbh->quote( $w1000[$i] );
}


$sql = "SELECT `Kategorie` FROM `test`.`kategorien`
       WHERE `Kategorie`
       IN (" . implode(',', $w1000 ) . ")";

$sth = $dbh->prepare( $sql );
$sth->execute();

$founds=[];
while ( $result = $sth->fetch( PDO::FETCH_ASSOC ) ) {
	$founds[] = $result['Kategorie'];
}

echo "Ermitteln der Übereinstimmungen aus der Datenbank: "
. ( hrtime( true ) - $startT ) / 1e+6
. " ms.\n";

#print_r( $founds );

Witzigerweise ging das SQL schneller, wenn ich den Primary Key auf die Kategorien gedroppt habe. Indexe helfen nicht immer.

Das ist für kurze Tabellen bekannt. Aber, dass Indexe eine Abfrage verlangsamen habe ich noch nie gehört. Kann es sein, dass die Antwort aus einem Cache des DBMS kam? Bei mir ist das so:

Erster Start:

Ermitteln der Übereinstimmungen aus der Datenbank: 5.63705 ms.

Zweiter Start:

Ermitteln der Übereinstimmungen aus der Datenbank: 1.010887 ms.

Wenn ich die Tabelle leere und neu einlese sind es nämlich wieder 5-7 ms... Aufmerksame Leser werden aber gemerkt haben, dass in PHP der reine Vergleich 0,12 ms gedauert hat… Ich sollte erwähnen, dass die Datenbank auf dem localhost liegt und via socket befragt wird. Geht das über das Netz kommt schon wegen Paketlaufzeit noch etwas hinzu. Das kann aber auch für Dateisysteme gelten (nfs-mount?).

Aber die Ergebnisse stützen meine Aussage, dass, abhängig von der Aufgabe, eine Lösung des Vergleiches außerhalb der Datenbank sinnvoll sein kann.