Массовые вставки MySQL в 2 раза медленнее PHP - PullRequest
0 голосов
/ 13 ноября 2018

Я тестировал Go в надежде использовать его для нового сайта и хотел убедиться, что он работает так же быстро или быстрее, чем PHP.Поэтому я выполнил базовый тест, выполняющий массовые вставки в Go и PHP, потому что мне понадобятся массовые вставки.

В моих тестах использовались транзакции, подготовленные операторы, тот же компьютер, точно такое же определение таблицы, без индекса, кроме PKи та же логика в функции.

Результаты:

  • 100k Вставок в PHP (mysqli) составил 4,42 секунды
  • 100k Вставок в Go (Go-MySQL-Драйвер): 9,2 секунды

Используемый мной драйвер go mysql является самым популярным драйвером Go-MySQL-Driver, найденным здесь: https://github.com/go-sql-driver/mysql

I'mИнтересно, может ли кто-нибудь сказать мне, правильно ли настроен мой код в go или это просто так?

Функции добавляют немного изменчивости к нескольким переменным строки, поэтому каждая строка не одинакова.

Функция Go:

func fill_table(w http.ResponseWriter, r *http.Request, result_string *string, num_entries_to_add int) {
    defer recover_show_error(result_string)

    db := getDBConn()
    defer db.Close()

    var int_a int = 9  
    var int_b int = 4  

    var int_01 int = 1           
    var int_02 int = 1451628000 // Date Entered  (2016-1-1, 1am)
    var int_03 int = 11         
    var int_04 int = 0
    var int_05 int = 0

    var float_01 float32 = 90.0 // Value
    var float_02 float32 = 0
    var float_03 float32 = 0

    var text_01 string = "" 
    var text_02 string = ""
    var text_03 string = ""

    start_time := time.Now()

    tx, err := db.Begin()
    if err != nil {
        panic(err)
    }

    stmt, err := tx.Prepare("INSERT INTO " + TABLE_NAME +
        "(`int_a`,`int_b`,`int_01`,`int_02`,`int_03`,`int_04`,`int_05`,`float_01`,`float_02`,`float_03`,`text_01`,`text_02`,`text_03`) " +
        "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)")

    if err != nil {
        panic(err)
    }
    defer stmt.Close()

    var flip int = 0
    for i := 0; i < num_entries_to_add; i++ {

        flip = ((int)(i / 500)) % 2
        if flip == 0 {
            float_01 += .1 // add to Value
        } else {
            float_01 -= .1 // sub from Value
        }

        int_02 += 1 // add a second to date.

        _, err = stmt.Exec(int_a, int_b, int_01, int_02, int_03, int_04, int_05, float_01, float_02, float_03, text_01, text_02, text_03)
        if err != nil {
            panic(err)
        }
    }

    err = tx.Commit()
    if err != nil {
        panic(err)
    }

    elapsed := time.Since(start_time)
    *result_string += fmt.Sprintf("Fill Table Time = %s</br>\n", elapsed)
}

Функция PHP:

function FillTable($num_entries_to_add){ 

    $mysqli= new mysqli("localhost", $GLOBALS['db_username'], $GLOBALS['db_userpass'], $GLOBALS['database_name']);
    if ($mysqli->connect_errno == 0) {

        $int_a = 9; 
        $int_b = 4; 

        $int_01 = 1; 
        $int_02 = 1451628000; // Date Entered  (2016-1-1, 1am)
        $int_03 = 11; 
        $int_04 = 0;         
        $int_05 = 0;         

        $float_01 = 90.0; // Value
        $float_02 = 0;
        $float_03 = 0;

        $text_01 = ""; 
        $text_02 = "";
        $text_03 = "";


        $mysqli->autocommit(FALSE);     // This Starts Transaction mode. It will end when you use mysqli->commit();         

        $sql = "INSERT INTO " . $GLOBALS['table_name'] . 
            "(`int_a`,`int_b`,`int_01`,`int_02`,`int_03`,`int_04`,`int_05`,`float_01`,`float_02`,`float_03`,`text_01`,`text_02`,`text_03`) " . 
            "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)";

        $start_time = microtime(true);

        if($stmt = $mysqli->prepare($sql)) {
            $stmt->bind_param('iiiiiiidddsss', $int_a, $int_b, $int_01, $int_02, $int_03, $int_04, $int_05, $float_01, $float_02, $float_03, $text_01, $text_02, $text_03);

            $flip = 0;
            for ($i = 1; $i <= $num_entries_to_add; $i++) {
                $flip = ((int)($i / 500)) % 2;
                if ($flip == 0) {
                    $float_01 += .1;    // add Value
                }
                else {
                    $float_01 -= .1;    // sub Value
                }

                $int_02 += 1;       // add a second to date.

                $stmt->execute(); //Executes a prepared Update 
            }

            $mysqli->commit();  // Transaction mode ends now    
            $stmt->close();  //Close statement
        }

        $execute_time = microtime(true) - $start_time;
        echo $GLOBALS['html_newline'] . $GLOBALS['html_newline'] . 
            'FillDataEntryTable Speed: '.$execute_time.' sec' . $GLOBALS['html_newline'] . $GLOBALS['html_newline'];

        $thread_id = $mysqli->thread_id;    // Get MySQL thread ID
        $mysqli->kill($thread_id);          // Kill MySQL Server connection
        $mysqli->close();                   // Close MySQL Server connection
    }        
}

1 Ответ

0 голосов
/ 18 ноября 2018

В своем тестировании, чтобы найти язык, который я хочу использовать для моего нового сайта, я экспериментировал с php, golang и java. У меня нет большого опыта работы с любым из языков, поэтому все, что я здесь скажу, может быть исправлено кем-то в будущем.

Моим основным тестом были пакетные вставки в базу данных mysql, потому что она мне понадобится для приложения.

Я хотел отойти от php, потому что это некомпилированный старый язык сценариев, который медленнее во многих вещах, чем golang и java. Это также неловкий синтаксис для многих вещей. Однако php mysqli на самом деле в 2 раза быстрее, чем golang, для больших «транзакций», если только вы не неловко вызываете много подпрограмм, чтобы разделить работу.

Во время испытаний и исследований я обнаружил несколько вещей.

PHP-API «транзакции» mysqli, вероятно, использует какие-то пакетные операции для выполнения «транзакции», потому что у mysqli нет отдельных пакетных функций, и транзакции выполняются быстрее, чем одиночные вставки. Но в большинстве других языков транзакции не выполняют автоматическую пакетную обработку всего и даже не увеличивают время выполнения. Это просто механизм для отката всего в транзакции, если что-то пойдет не так. Что увеличивает время выполнения на других языках, так это использование пакетов.

Но одной из больших проблем с интерфейсом go mysql в настоящее время, по-видимому, является отсутствие реальной поддержки пакетных операций. Самым близким, что я получил, было создание Jerry Rig и создание моей собственной пакетной операции, как указано в этом посте ( golang - mysql Вставить несколько данных одновременно? ). Делая это, я смог получить время выполнения от 9,2 до 3,9 с, не вызывая другие процедуры го. Но поскольку реальной поддержки этому нет, пакетная операция возвращает только один результирующий набор для первой операции пакета. Это бесполезно для меня, потому что мне нужно возвращать идентификаторы autoinc для моих вставленных строк. Были и другие проблемы с этой настройкой, в которые я не буду вдаваться.

Итак, наконец, я попробовал Java на сервере Tomcat. Установка Tomcat / Java немного сложнее, чем Go, но программирование на Java было намного проще и естественнее. JDBC - это отличный драйвер с полной поддержкой простых пакетных операций с подготовленными операторами. Он сделал 100 тысяч вставок всего за 1 секунду Это явный победитель в моей книге. Плюс Java-синтаксис гораздо более естественный, чем golang IMO.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...