Загружаем данные в postgresql

в 2:56, , рубрики: benchmark, golang, postgresql, postgresql 9.3, метки: , ,

Прочитал статью о разгоне производительности операций вставок в СУБД Oracle при помощи транзакций на Java. Так как в данный момент я работаю с postgresql, то решил проверить, сколько выдаст эта СУБД в связке с голангом.
Используемый стек: golang-1.1.2 + postgresql-9.3.1.
Для запуска программы понадобится голанговский драйвер для postgresql. Я пользуюсь драйвером github.com/lib/pq, который установил при помощи команды go get -u github.com/lib/pq.

Среда тестирования.

Домашний десктоп с archlinux-x86_64, kernel-3.11.5, 4ГБ RAM (на момент теста было свободно примерно 1.2ГБ), обычный старенький шпиндельный HDD. Постгрес более-менее настроен (увеличен shared_buffers до 768МБ и max_connections до 1000, + еще какой-то тюнинг), но без хардкора.
Для чистоты эксперимента не делал никаких гороутин — все в 1 поток.

Текст программы

/* sql_insertion_test01.go 
 * Synthetic test for simple insert operations into postgresql database
 * Call: ./sql_insertion_test01
 * Pls, do not use name "insert_test", because this name is always used by go-pkg-system
 */
package main

import (
    _ "github.com/lib/pq"
    "database/sql"
    "fmt"
    "time"
)

const DB_CONNECT_STRING = 
    "host=localhost port=5432 user=your_role password=your_password dbname=your_database sslmode=disable"

func main() {

    db, err := sql.Open("postgres", DB_CONNECT_STRING)
    defer db.Close()

    if err != nil {
        fmt.Printf("Database opening error -->%vn", err)
        panic("Database error")
    }

    init_database(&db)
    make_insertion(&db)

}

/*-----------------------------------------------------------------------------*/
func init_database(pdb **sql.DB) {

    db := *pdb

    init_db_strings := []string{
        "DROP SCHEMA IF EXISTS sb CASCADE;",
        "CREATE SCHEMA sb;",
        //be careful - next multiline string is quoted by backquote symbol
        `CREATE TABLE sb.test_data(
         id serial,
         device_id integer not null,
         parameter_id integer not null,
         value varchar(100),
         event_ctime timestamp default current_timestamp,
         constraint id_pk primary key (id));`}

    for _, qstr := range init_db_strings {
        _, err := db.Exec(qstr)

        if err != nil {
            fmt.Printf("Database init error -->%vn", err)
            panic("Query error")
        }
    }
    fmt.Println("Database rebuilded successfully")
}

/*-----------------------------------------------------------------------------*/
func make_insertion(pdb **sql.DB) {

    db := *pdb
    const TEST_NUMBER = 400000

    // backquotes for next multiline string
    const INSERT_QUERY = `insert into sb.test_data(device_id, parameter_id, value)
                                  values ($1, $2, $3);`

    insert_query, err := db.Prepare(INSERT_QUERY)
    defer insert_query.Close()

    if err != nil {
        fmt.Printf("Query preparation error -->%vn", err)
        panic("Test query error")
    }

    t1 := time.Now()

    for i := 0; i < TEST_NUMBER; i++ {

        _, err = insert_query.Exec(i, i, "0")

        if err != nil {
            fmt.Printf("Query execution error -->%vn", err)
            panic("Error")
        }
    }

    t2 := time.Since(t1)

    fmt.Printf("%v queries are executed for %v seconds (%v per second)n",
        TEST_NUMBER, t2.Seconds(), TEST_NUMBER/t2.Seconds())

    // do not forget clean up after work )
    //_, err = db.Query("TRUNCATE sb.test_data;")
}

Как видно из текста — никаких специальных выделений в транзакции, гороутин, временных таблиц и прочих ухищрений — прямой ввод.
Ну разумеется связка prepare-exec.

Результаты

Результаты — 16000-17000 вставок в секунду на моей машине.
Результаты не зависят от константы TEST_NUMBER (ставил 1000, 2000, 4000, 40000 и остановился на 400000). Возможно на больших значениях и произойдет затык, но думаю, что для текущих целей такой производительности хватает.
Рассчитывал получить худшие цифры и планировал повозиться с транзакциями, но не понадобилось.

Выводы

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

Автор: Forked

Источник

Поделиться

* - обязательные к заполнению поля