Πιο γρήγορα στρινγκς!

Σε αυτή την περιοχή μπορείτε να βρείτε ή να αναζητήσετε πληροφορίες σχετικές με την PHP

Συντονιστές: WebDev Moderators, Super-Moderators, PHP Moderators

Απάντηση
Άβαταρ μέλους
Christianago
Δημοσιεύσεις: 332
Εγγραφή: 12 Νοέμ 2009 13:36

Πιο γρήγορα στρινγκς!

Δημοσίευση από Christianago » 09 Ιούλ 2011 20:06

Εχω το παρακατω προγραμμα που παραγει τυχαιες συμβολοσειρές με βαση ενα ευρος τιμών και τις εισάγει σε ένα πίνανα στη ΒΔ.
Το προγραμμα λειτουργει σωστα εισαγει στη ΒΔ εκατονταδες εγγραφες το δεπτερολεπτο.
Το προβλημα μου ειναι αν γινεται η παραγωγή strings να ειναι πιο γρηγορη ή ακόμα και η εισαγωγή στη ΒΔ (μηχανή MyISAM), καθώς ο χρόνος ειναι αρκετα σημαντικός για την εφαρμογή.

Κώδικας: Επιλογή όλων

@$db = mysqli_connect('localhost', '****', '****', 'wordlist');

function random_gen(){
 
$characters = "0123456789abcdefghijklmnopqrstuvwxyz";
$string = "";        

for &#40;$i = 0; $i < 8; $i++&#41;&#123; 
@$string .= $characters&#91;mt_rand&#40;0, strlen&#40;$characters&#41;&#41;&#93;;  
&#125;

return $string;
  
&#125;

$i = 0;
while &#40;$i < 1000000&#41;&#123;

//echo "<br>".
    
$random_string = random_gen&#40;&#41;; 

mysqli_query&#40;$db, "INSERT words &#40;ID&#41; VALUES &#40;'$random_string'&#41;"&#41;;

$i++;
&#125;

Άβαταρ μέλους
Rapid-eraser
WebDev Moderator
Δημοσιεύσεις: 6851
Εγγραφή: 05 Απρ 2003 17:50
Τοποθεσία: Πειραιάς
Επικοινωνία:

Πιο γρήγορα στρινγκς!

Δημοσίευση από Rapid-eraser » 09 Ιούλ 2011 21:38

Όσον αφορά την βάση δεδομένων μπορείς να κάνεις ένα optimize βάζοντας στο κάθε insert περισσότερες από μία πχ 1000 εγγραφές. Για το νούμερο θα πρέπει να μιλήσεις με τον database administrator σου που θα σου πει για την εγκατάσταση σου πιο είναι το optimal.

Γενικός η mySQL δεν ενδίκνιτε για καταστάσεις που τα writes είναι περισσότερα από τα reads. Ίσως μία λύση σε MongoDB ή Chouchdb αναλόγως αν χρειάζεσαι partial updates θα σου προσφέρει πολύ μεγαλύτερες ταχύτητές.

Τέλος για πιο γρήγορη δημιουργία strings προφανώς η php δεν είναι αυτό που σου χρειάζεται αλλά πχ κάτι σε C.
Cu, Rapid-eraser, Tα αγαθά copies κτώνται.
Love is like oxygen, You get too much you get too high
Not enough and you're gonna die, Love gets you high

Άβαταρ μέλους
greekbytes
WebDev Moderator
Δημοσιεύσεις: 2438
Εγγραφή: 15 Νοέμ 2002 15:42
Τοποθεσία: Αθήνα
Επικοινωνία:

Πιο γρήγορα στρινγκς!

Δημοσίευση από greekbytes » 09 Ιούλ 2011 21:49

Rapid ++ :)

Μπορείς και να κάνεις ένα υποτυπώδες "random" string κατευθείαν στη mySQL κάπως έτσι:

Κώδικας: Επιλογή όλων

INSERT INTO `words` &#40;`ID`&#41; VALUES &#40;SUBSTRING&#40;MD5&#40;RAND&#40;&#41;&#41; FROM 1 FOR 8&#41;&#41;

Άβαταρ μέλους
Christianago
Δημοσιεύσεις: 332
Εγγραφή: 12 Νοέμ 2009 13:36

Πιο γρήγορα στρινγκς!

Δημοσίευση από Christianago » 09 Ιούλ 2011 22:05

Θα δοκιμασω ολες τις λυσεις ευχαριστω.

Κώδικας: Επιλογή όλων

INSERT INTO `words` &#40;`ID`&#41; VALUES &#40;SUBSTRING&#40;MD5&#40;RAND&#40;&#41;&#41; FROM 1 FOR 8&#41;&#41;
Αυτη ειναι ψευδοτυχαια συμβολοσειρα ή κανονική; Το ευρος τιμων πώς μπορω να το ενσωματωσω σε αυτη τη γραμμη;
Εχω ασχοληθει μονο με Mysql. Οσον αφορα τη MongoDB ειναι ευκολη στην εγκατασταση;
Απλα την κατεβαζω και ρολάρω;
Εγω ειμαι ο admin της βασης το optimization που λες πως το κανω;
Τελος τι χρειαζομαι για να συνδεθω σε Mysql με C?

pimpogio
Δημοσιεύσεις: 1080
Εγγραφή: 28 Δεκ 2010 14:08

Πιο γρήγορα στρινγκς!

Δημοσίευση από pimpogio » 09 Ιούλ 2011 22:53

1) drop τα indexes αν εχεις
2) Βαζεις innodb engine οχι myisam που εχεις
3) για αυτο τον πολυ απλο κωδικα χρησιμοποιεις
stored procedure οχι php η στην τελικη αν θες php
χρησιμοποιεις prepared statment.
Αυτο που εχεις αυτη τη στιγμη query μεσα σε loop
το οποιο δεν ειναι prepared ειναι λογικο να καθυστερει.

gvre
Δημοσιεύσεις: 992
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Πιο γρήγορα στρινγκς!

Δημοσίευση από gvre » 09 Ιούλ 2011 23:56

Αλλάζοντας λίγο τη συνάρτησή σου από

Κώδικας: Επιλογή όλων

function random_gen&#40;&#41;
&#123; 
	$characters = "0123456789abcdefghijklmnopqrstuvwxyz"; 
  	$string = "";        

	for &#40;$i = 0; $i < 8; $i++&#41;&#123; 
		@$string .= $characters&#91;mt_rand&#40;0, strlen&#40;$characters&#41;&#41;&#93;;  
  	&#125; 

  	return $string; 
&#125; 
σε

Κώδικας: Επιλογή όλων

function random_gen&#40;&#41;
&#123;
        static $characters = "0123456789abcdefghijklmnopqrstuvwxyz";
        static $maxLen = 35; // 36 - 1

        $string = "";
        for &#40;$i = 0; $i < 8; ++$i&#41;
                $string .= $characters&#91;mt_rand&#40;0, $maxLen&#41;&#93;;
        return $string;
&#125;
ο χρόνος που χρειαζόταν το laptop μου για 1.000.000 τυχαία strings μειώθηκε από 68 δευτερόλεπτα σε 32 (σημαντικό ρόλο στη μείωση του χρόνου έπαιξε η αντικατάσταση της strlen($characters) από μεταβλητή).
Αν συνδυάσεις την τροποποιημένη συνάρτηση με transactions και prepared statements θα δεις σημαντική μείωση στο χρόνο που χρειάζεται το script.

Κάτι βασικό που δεν ανέφερες, το οποίο ίσως επηρεάσει τον τρόπο υλοποίησης, είναι η χρήση που θα γίνει στα συγκεκριμένα random strings.

ps. Αν θέλεις να κερδίσεις περίπου 3 δευτερόλεπτα επιπλέον, μπορείς να χρησιμοποιήσεις την παρακάτω συνάρτηση.

Κώδικας: Επιλογή όλων

function random_gen&#40;&#41;
&#123;
        static $characters = "0123456789abcdefghijklmnopqrstuvwxyz";

        return  $characters&#91;mt_rand&#40;0, 35&#41;&#93;
                . $characters&#91;mt_rand&#40;0, 35&#41;&#93;
                . $characters&#91;mt_rand&#40;0, 35&#41;&#93;
                . $characters&#91;mt_rand&#40;0, 35&#41;&#93;
                . $characters&#91;mt_rand&#40;0, 35&#41;&#93;
                . $characters&#91;mt_rand&#40;0, 35&#41;&#93;
                . $characters&#91;mt_rand&#40;0, 35&#41;&#93;
                . $characters&#91;mt_rand&#40;0, 35&#41;&#93;;
&#125;

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Πιο γρήγορα στρινγκς!

Δημοσίευση από dva_dev » 10 Ιούλ 2011 00:05

Κάνε μια δοκιμή με κάτι τέτοιο

Κώδικας: Επιλογή όλων

@$db = mysqli_connect&#40;'localhost', '****', '****', 'wordlist'&#41;;

function random_gen&#40;&#41;
&#123;
    $characters = "0123456789abcdefghijklmnopqrstuvwxyz";
    $len = strlen&#40;$characters&#41;;

    $string = "";
    for &#40;$i = 0; $i < 8; ++$i&#41; $string .= $characters&#91;mt_rand&#40;0, $len&#41;&#93;;
    return $string;
&#125;

$i = 0;
while &#40;$i < 10000&#41;
&#123;
    $random_string = random_gen&#40;&#41;; 
    $query = '';
    for &#40; $j=0; $j<100; ++$j&#41; $query .= random_gen&#40;&#41; . "'&#41;,&#40;'";
    $query = "INSERT words &#40;ID&#41; VALUES &#40;'$query'&#41;";
    mysqli_query&#40;$db, $query&#41;;
    $i++;
&#125;

pimpogio
Δημοσιεύσεις: 1080
Εγγραφή: 28 Δεκ 2010 14:08

Πιο γρήγορα στρινγκς!

Δημοσίευση από pimpogio » 10 Ιούλ 2011 00:34

Η καθυστερηση δεν ειναι στην δημιουργία των strings..
ειναι στο επιπεδο της βασης.

οποτε αλλαγη στη συναρτηση δημιουργίας των strings
ελαχιστα θα βοηθησει...

Η εργασια στην μνημη ειναι κατα πολυ ταχυτερη απο το δισκο το bottleneck ειναι η εγγραφη στο δισκο και η επικοινωνια βαση δεδομενων δηλαδη στο i/o

αρκει να σκευτεις οτι το string ειναι μερικα bytes
και το block στο δισκο ειναι συνηθως 4k

αλλη αποδοση εχει να γραφεις το block με 1 προσβαση στο δισκο και αλλη με 50.

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Πιο γρήγορα στρινγκς!

Δημοσίευση από dva_dev » 10 Ιούλ 2011 00:34

Για μένα πάντως η "μεγάλες" καθυστερήσεις προκαλούνται γενικά από επαναλαμβανόμενες κλήσεις συναρτήσεων που φέρνουν πάντα τα ίδια αποτελέσματα (π.χ. strlen εδώ) και από τα συνεχόμενα queries στη βάση δεδομένων.
Δεν έχω κάνει δοκιμές για να δω τι/πόσο κερδίζεις, αλλά με τον παραπάνω κώδικα που κάνει 100 τιμές insert κάθε φορά και όχι 1, μειώνεις τα insert statements στο 1% φαντάζομαι ότι θα έχεις σημαντική βελτίωση. Κάνε μερικές δοκιμές μήπως μπορείς να ρίχνεις περισσότερα (π.χ. 200) κάθε φορά.

gvre
Δημοσιεύσεις: 992
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Πιο γρήγορα στρινγκς!

Δημοσίευση από gvre » 10 Ιούλ 2011 00:45

pimpogio έγραψε:Η καθυστερηση δεν ειναι στην δημιουργία των strings..
ειναι στο επιπεδο της βασης.

οποτε αλλαγη στη συναρτηση δημιουργίας των strings
ελαχιστα θα βοηθησει...
Η καθυστέρηση είναι και στη δημιουργία των strings. Στη συγκεκριμένη περίπτωση το κέρδος από 2-3 μικρές αλλαγές στη συνάρτηση είναι 40" (28 από 68 δευτερόλεπτα που χρειαζόταν πριν). Αν αυτό το συνδυάσει με transactions, prepared statements και τα μαζικά inserts που αναφέρει ο dva_dev, θα δει μεγάλη διαφορά στους χρόνους.

pimpogio
Δημοσιεύσεις: 1080
Εγγραφή: 28 Δεκ 2010 14:08

Πιο γρήγορα στρινγκς!

Δημοσίευση από pimpogio » 10 Ιούλ 2011 00:54

στη συγκεκριμενη περιπτωση ελαχιστα εχει να κανει αυτο...
εδω το i/o ειναι το bottleneck
* βαζεις prepared statment η stored procedure με πολλα values ανα insert για να γεμισεις το block του δισκου
* βαζεις innodb
* κανεις drop τα indexes
* εναλλακτικα κανεις προυπολογισμο των strings
σε file και φορτωνεις το file

gvre
Δημοσιεύσεις: 992
Εγγραφή: 14 Οκτ 2010 11:34
Τοποθεσία: Ηράκλειο Κρήτης
Επικοινωνία:

Πιο γρήγορα στρινγκς!

Δημοσίευση από gvre » 10 Ιούλ 2011 01:04

Ίσως τα 40" για εσένα να είναι ελάχιστος χρόνος. Για εμένα και αρκετούς άλλους πάντως δεν είναι.

pimpogio
Δημοσιεύσεις: 1080
Εγγραφή: 28 Δεκ 2010 14:08

Πιο γρήγορα στρινγκς!

Δημοσίευση από pimpogio » 10 Ιούλ 2011 01:24

40'' στο 1 μυριο ειναι η καθυστερηση στα strings
η καθυστερηση στα 1 μυριο inserts ειναι παρα πολυ παραπανω που κανει τα 40'' ασημαντα αυτο λεω.

Άβαταρ μέλους
Christianago
Δημοσιεύσεις: 332
Εγγραφή: 12 Νοέμ 2009 13:36

Πιο γρήγορα στρινγκς!

Δημοσίευση από Christianago » 10 Ιούλ 2011 01:33

Παιδια επομενως για να καταληξουμε καπου ακουστηκαν πολλες ενδιαφερουσες ιδεες.
Οσο πιο γρηγορα γινονται ολα τοσο καλυτερο ειναι σημαντικο. Συνοψιζουμε:

Στη ΒΔ
engine: Innodb με απενεργοποιημενα τα indexes,
data type: char->8
να θεσω κλειδι η δεν εχει νοημα;

Μετα εχω τον κωδικα:

Κώδικας: Επιλογή όλων

@$db = mysqli_connect&#40;'localhost', '*', '*', 'wordlist'&#41;;

function random_gen&#40;&#41;&#123;
    
    static $characters = "0123456789abcdefghijklmnopqrstuvwxyz";
    static $len = 35; 

    $string = "";
    
        return  $characters&#91;mt_rand&#40;0, $len&#41;&#93;
                . $characters&#91;mt_rand&#40;0, $len&#41;&#93;
                . $characters&#91;mt_rand&#40;0, $len&#41;&#93;
                . $characters&#91;mt_rand&#40;0, $len&#41;&#93;
                . $characters&#91;mt_rand&#40;0, $len&#41;&#93;
                . $characters&#91;mt_rand&#40;0, $len&#41;&#93;
                . $characters&#91;mt_rand&#40;0, $len&#41;&#93;
                . $characters&#91;mt_rand&#40;0, $len&#41;&#93;; 
&#125;

$i = 0;
while &#40;$i < 1000&#41;&#123;
    
    $random_string = random_gen&#40;&#41;;
    $query = '';
    
    for &#40;$j = 0; $j < 200; ++$j&#41;
    
        $query .= random_gen&#40;&#41; . "'&#41;,&#40;'";
        $query = "INSERT words &#40;ID&#41; VALUES &#40;'$query'&#41;";
        mysqli_query&#40;$db, $query&#41;;
        
    $i++;
&#125; 

Μου μενουν τα:transactions, prepared statements τα οποια ξερω τι ειναι αλλα δεν εχω κανει ποτε. Μπορειτε να μου δωσετε ενα παραδειγμα να καταλαβω;
Επιπλεον ξερω οτι η load_data_infile οπως αναφερθηκε εμμεσως πριν νομιζω οι εισαγωγες γινονται 20 φορες ταχυτερα. Αξιζει να το δοκιμασω;

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Πιο γρήγορα στρινγκς!

Δημοσίευση από dva_dev » 10 Ιούλ 2011 02:04

Από μια δοκιμή που έχω κάνει σε ένα μηχάνημα μου (για 100.000 εγγραφές, όχι 1.000.000 αλλά χοντρικά 10πλασιάζεις τους χρόνους) έχω τα εξής:
Σε InnoDB (Χωρίς index)
[root@Centos test4]# php strings.php
Run at: 141.55780 Rows: 100000
[root@Centos test4]# php strings1.php
Run at: 3.66610 Rows: 100000
[root@Centos test4]#
Σε MyIsam (Χωρίς index)
[root@Centos test4]# php strings2.php
Run at: 90.90552 Rows: 100000
[root@Centos test4]# php strings3.php
Run at: 2.41635 Rows: 100000
[root@Centos test4]#
strings.php, (το strings2 είναι ίδιο αλλά χρησιμοποιεί άλλο πίνακα σε MyISAM)

Κώδικας: Επιλογή όλων

<?php
function microtime_float&#40;&#41;
&#123;
    list&#40;$usec, $sec&#41; = explode&#40;' ', microtime&#40;&#41;&#41;;
    return &#40;&#40;float&#41;$usec + &#40;float&#41;$sec&#41;;
&#125;

$tb = microtime_float&#40;&#41;;

@$db = mysqli_connect&#40;'localhost', '*****', '*****', 'testdb'&#41;; 
mysqli_query&#40;$db, 'set names utf8'&#41;; 
mysqli_query&#40;$db, 'truncate table table1'&#41;; 

function random_gen&#40;&#41;&#123; 
  
$characters = "0123456789abcdefghijklmnopqrstuvwxyz"; 
$string = "";        

for &#40;$i = 0; $i < 8; $i++&#41;&#123; 
@$string .= $characters&#91;mt_rand&#40;0, strlen&#40;$characters&#41;-1&#41;&#93;;  
&#125; 

return $string; 
  
&#125; 

$i = 0; 
while &#40;$i < 100000&#41;&#123; 

$random_string = random_gen&#40;&#41;; 

mysqli_query&#40;$db, "INSERT INTO table1&#40;ID&#41; VALUES &#40;'$random_string'&#41;"&#41;; 

$i++; 
&#125;

$te = microtime_float&#40;&#41;;

mysqli_real_query&#40;$db, 'select count&#40;*&#41; from table1'&#41;;
$result = mysqli_use_result&#40;$db&#41;;
$row = mysqli_fetch_row&#40;$result&#41;;

echo 'Run at&#58; ', number_format&#40;$te-$tb, 5&#41;, ' Rows&#58; ', $row&#91;0&#93;, "\n";
?>
strings1.php, (το strings3 είναι ίδιο αλλά χρησιμοποιεί άλλο πίνακα σε MyISAM)

Κώδικας: Επιλογή όλων

<?php
function microtime_float&#40;&#41;
&#123;
    list&#40;$usec, $sec&#41; = explode&#40;' ', microtime&#40;&#41;&#41;;
    return &#40;&#40;float&#41;$usec + &#40;float&#41;$sec&#41;;
&#125;

$tb = microtime_float&#40;&#41;;

@$db = mysqli_connect&#40;'localhost', '*****', '*****', 'testdb'&#41;; 
mysqli_query&#40;$db, 'set names utf8'&#41;;
mysqli_query&#40;$db, 'truncate table table1'&#41;;

function random_gen&#40;&#41;
&#123;
    $characters = "0123456789abcdefghijklmnopqrstuvwxyz";
    $string = "";
    $len = strlen&#40;$characters&#41;-1;

    for &#40;$i = 0; $i < 8; ++$i&#41;
    &#123;
        $string .= $characters&#91;mt_rand&#40;0, $len&#41;&#93;;
    &#125;
    return $string;
&#125;

for &#40;$i = 0; $i < 1000; $i++&#41;
&#123;
    $query = '';
    for &#40;$j = 1; $j < 100; ++$j&#41; $query .= random_gen&#40;&#41; . "'&#41;,&#40;'";

    mysqli_query&#40;$db, "INSERT INTO table1 &#40;ID&#41; VALUES &#40;'$query'&#41;"&#41;;
&#125;

$te = microtime_float&#40;&#41;;

mysqli_real_query&#40;$db, 'select count&#40;*&#41; from table1'&#41;;
$result = mysqli_use_result&#40;$db&#41;;
$row = mysqli_fetch_row&#40;$result&#41;;

echo 'Run at&#58; ', number_format&#40;$te-$tb, 5&#41;, ' Rows&#58; ', $row&#91;0&#93;, "\n";
?>
Οι πίνακες δημιουργήθηκαν έτσι:

Κώδικας: Επιλογή όλων

CREATE TABLE  `testdb`.`table1` &#40;
  `id` varchar&#40;8&#41; NOT NULL
&#41; ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE  `testdb`.`table2` &#40;
  `id` varchar&#40;8&#41; NOT NULL
&#41; ENGINE=MyISAM DEFAULT CHARSET=utf8;
Τελευταία επεξεργασία από το μέλος dva_dev την 10 Ιούλ 2011 02:09, έχει επεξεργασθεί 1 φορά συνολικά.

Απάντηση

Επιστροφή στο “PHP Προγραμματισμός”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 3 επισκέπτες