Pokazywanie postów oznaczonych etykietą pgloader. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą pgloader. Pokaż wszystkie posty

środa, 21 stycznia 2015

Import danych do MySQL lub PostgreSQL

Zacznijmy od MySQLa

Kiedyś napisałam dwa krótkie posty na temat exportu danych z MySQLa (znajdziecie go tutaj) i z PostgreSQLa (przeczytacie go tutaj) ale nie napisałam jak wykonać ich import. Czas uzupełnić tą lukę.

Zaimportujmy dane do tabeli test1.

mysql> show create table test1 \G
*************************** 1. row ***************************
       Table: test1
Create Table: CREATE TABLE `test1` (
  `c` int(11) DEFAULT NULL,
  `t` int(11) DEFAULT NULL,
  `cn` varchar(2) DEFAULT NULL,
  `d` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)



ela@skyler:~/Downloads$ mysqlimport -uroot -proot --lines-terminated-by='\n' --fields-terminated-by='\t' --local test test1.csv
test.test1: Records: 9765275  Deleted: 0  Skipped: 0  Warnings: 29193
ela@skyler:~/Downloads$ ll
total 212080
drwxr-xr-x  2 ela ela      4096 sty  5 13:15 ./
drwxr-xr-x 19 ela ela      4096 sty  5 13:15 ../
-rw-rw-r--  1 ela ela   1914553 sty  5 12:40 arch_geoip_201411.csv.tar.gz
-rw-rw-r--  1 ela ela   1299844 sty  5 12:39 PerconaToolkit-2.2.12.pdf
-r-xr-xr-x  1 ela ela 213941449 gru 30 16:47 test1.csv*
ela@skyler:~/Downloads$ wc -l test1.csv 
9765275 test1.csv

Do importu danych najlepiej użyć dedykowanej do tego binarki: mysqlimport, której dokumentację znajdziecie tutaj, a i wspominałam o tej binarce w innym poście, na temat dostępnych programów w instalacji serwera MySQL (Binarki MySQLa).

W trakcie importu danych mamy jednak dane, które musimy odpowiednio najpierw zapisać. Przykładowo znak NULL, który jak wcześniej zauważyliście spowodował wystąpienie Warningów przy imporcie, nie możemy zapisać jako string NULL tylko jako odpowiedni znak \N (link do dokumentacji). Dopiero wtedy zostanie poprawnie zaimportowany do MySQLa. Oto przykładowa zawartość pliku CSV:

ela@skyler:~/Downloads$ head test1.csv 
45 42 NULL 2014-11-01
45 42 NULL 2014-11-02
45 42 NULL 2014-11-06
45 42 NULL 2014-11-07
45 42 NULL 2014-11-08
45 42 NULL 2014-11-09
45 42 NULL 2014-11-09
45 42 NULL 2014-11-10
45 42 NULL 2014-11-10
45 42 NULL 2014-11-11

Importując je do naszej tabeli test1, dane z kolumny cn zostaną obcięte do dwóch znaków. W dodatku te dane zostały potraktowane jako stringi, a nie jak powinny jako znak NULL. Dlatego musimy poprawić nasz plik zanim zaczniemy proces importu:

ela@skyler:~/Downloads$ cat test1.csv | replace NULL '\N' > test2.csv
ela@skyler:~/Downloads$ head test2.csv 
45 42 N 2014-11-01
45 42 N 2014-11-02
45 42 N 2014-11-06
45 42 N 2014-11-07
45 42 N 2014-11-08
45 42 N 2014-11-09
45 42 N 2014-11-09
45 42 N 2014-11-10
45 42 N 2014-11-10
45 42 N 2014-11-11
ela@skyler:~/Downloads$ time mysqlimport -uroot -proot --lines-terminated-by='\n' --fields-terminated-by='\t' --local --columns=c,t,cn,d test test2.csv
test.test2: Records: 9765275  Deleted: 0  Skipped: 0  Warnings: 0

real 2m18.113s
user 0m0.059s
sys 0m0.188s

Dane został tym razem zapisane i zaimportowane do tabeli test2. Jeśli dobrze zauważyliście to tym razem wskazałam do jakich kolumn mają zostać zaimportowane dane przy pomocy opcji --column (-C).

Teraz czas przyszedł na PostgreSQL

No cóż. Nie ma sensu aby wspominać o tym ponownie. Ciąg dalszy tego posta był by tylko kopią innego napisanego przeze mnie jakiś czas temu o PGLoaderze (PGloader - narzędzie do importu danych). Mając prawa administracyjne do serwera, na którym stoi ten serwer, możecie bezpośrednio użyć polecenia COPY, a wcześniej przekopiować ten plik na ten serwer.

Miłej zabawy :-)

wtorek, 3 czerwca 2014

PGLoader v3

W ostatnim poście pisałam o narzędziu pgloader służący do importu danych do PostgreSQLa. Nowa wersja została przepisana w całości na język Common Lisp. Do zapisu i odczytu danych używane są dwa oddzielne wątki, które współdzielą pracę. To co się nie zmieniło to to, że do komunikacji PostgreSQL nadal używany jest protokołu COPY. Tutaj odsyłam do post na temat nowej wersji tego narzędzia.

Przykład instrukcji załadowania pliku CSV:

LOAD CSV  
   FROM '/root/pgloader_data.csv'
   INTO postgresql://root:password@188.226.251.1/pgloader?pgloader_test(c2,c3)
 
   WITH truncate,  
        skip header = 0,
        fields optionally enclosed by '"',  
        fields escaped by double-quote,  
        fields terminated by ','  
 
   SET client_encoding to 'utf8', 
 work_mem to '12MB', 
 standard_conforming_strings to 'on'
 
BEFORE LOAD DO  
    $$ drop table if exists pgloader_test; $$,  
    $$ create table pgloader_test (
        c1 serial,
        c2 varchar(20),  
        c3 integer
       );  
    $$; 


Ładujemy dane:

[root@niujork ~]$ pgloader  pgloader.load 
2014-06-03T14:54:53.046000Z LOG Starting pgloader, log system is ready.
2014-06-03T14:54:53.076000Z LOG Main logs in '/tmp/pgloader/pgloader.log'
2014-06-03T14:54:53.082000Z LOG Data errors in '/tmp/pgloader/'
2014-06-03T14:54:53.083000Z LOG Parsing commands from file #P"/root/pgloader.load"
2014-06-03T14:54:59.686000Z ERROR Database error 22P02: invalid input syntax for integer: "sldkfhg"
CONTEXT: COPY pgloader_test, line 2, column c3: "sldkfhg"


                    table name       read   imported     errors            time

                   before load          2          2          0          2.701s
------------------------------  ---------  ---------  ---------  --------------
                 pgloader_test     219175     219174          1         18.568s
------------------------------  ---------  ---------  ---------  --------------
------------------------------  ---------  ---------  ---------  --------------
             Total import time     219175     219174          1         21.269s


Ładujemy dane gdzie pierwsza komuna jest varchar, a druga integer. Dla niepoprawnych danych, narzędzie wyświetla błędy ale reszta danych zostanie zaimportowana poprawnie.

Innym dodatkowym atutem jest możliwość ładowania danych z innych systemów bazodanowych: MySQL, SQLite czy dBase, a także odczytywanie danych z plików zarchiwizowanych czy danych o stałej szerokości. Jeśli musicie zaimportować dane do PostgreSQL, to polecam to narzędzie. Może się wam bardzo przydać.

Zainteresowanych odsyłam do dokumentacji tutaj.


wtorek, 27 maja 2014

PGLoader - narzędzie do importu danych

PGLoader (użyłam wersji 2.3.2) jest narzędziem napisanym w pythonie, służącym do importu danych. Nie wiem czy mieliście kiedyś styczność z tym narzędziem. Narzędzie dzieli dane na paczki (maksymalną wielkość paczek możemy sami ustawić). Tworzy także sekcje, które są odpowiedzialne za ładowanie danych do bazy. Każda z sekcji ma swój własny wątek, a ich ilość także jest konfigurowalna.

Jest bardzo prosty w obsłudze ale musimy go najpierw skonfigurować. Przykładowy plik konfiguracyjny zawiera (pgloader.conf jest domyślnym plikiem konfiguracyjnym):

[pgsql]
base = pgloader

host = 127.0.0.1 
port = 7432 
user = postgres
pass = 

log_file            = /tmp/pgloader.log
log_min_messages    = INFO 
client_min_messages = WARNING

lc_messages         = C 
pg_option_client_encoding = 'utf-8'
pg_option_standard_conforming_strings = on
pg_option_work_mem = 128MB 

copy_every      = 20000                               
null         = "" 
empty_string = "\ "
max_parallel_sections = 4 

Znaczenie parametrów:
  • base - baza danych, do której będą ładowane dane
  • host / post / user / pass - dane do połączenia się do bazy danych
  • log_file - ścieżka do pliku logowania
  • log_min_messages / client_min_messages -poziom logowania danych
  • lc_messages - ustawia zmienną LC_MESSAGES dla połączenia
  • pg_option_<foo> - ustawa dowolną zmienną <foo> dla połączenia
  • copy_every - maksymalna ilość danych importowana przez paczkę
  • null / empty_string - parametry są związane z interpretacją danych w tekście lub w plikach CSV. Zmienne odpowiednio definiują jak wartości NULL/puste stringi są reprezentowane w importowanych danych

    Przykład danych:

    cat test_copy.csv 
    "",2
    ,
    "\ ",3
    'eeee',0
     ee eee,9
    eee,
    

    Dla ustawień przedstawionych powyżej dane będą zapisane w bazie następująco:

    select c2,c3 from test_copy;
    +---------+------+
    |   c2    |  c3  |
    +---------+------+
    | NULL    |    2 |
    | NULL    | NULL |
    |         |    3 |
    | 'eeee'  |    0 |
    |  ee eee |    9 |
    | eee     | NULL |
    +---------+------+
    (6 rows)
    
    Time: 0,400 ms
    
  • max_parallel_sections - ilość paczek do załadowania w tym samym czasie


Przejdźmy dalej do ustawienia formatu plików. Ja chcę zaimportować plik CSV, a to są moje ustawienia:

[csv]
table        = pgloader_table
format       = csv
filename     = csv_without_header.data
field_sep    = ,
quotechar    = "
columns      = c1, c2, c3, c4, c5, c6, c7, c8, c9

Dane zostaną zapisane w tabeli pgloader_table i zostaną zaimportowane z pliku csv_witout_header.data Parametr kolumn wskazuje kolumny, w których mają zostać zapisane dane.


Uruchamiany PGLoader

W poniższym przykładzie użyłam opcji:
  • T (--truncate) - wymuś czyszczenie tabeli przed załadowaniem
  • s (--summary) - wypisz podumowanie
  • v (--verbose) - wypisz informacje o przetrważaniu
  • c (-c CONFIG, --config=CONFIG) - ścieżka do pliku konfiguracyjnego

pgloader -Tsvc pgloader.conf csv
pgloader     INFO     Logger initialized
pgloader     WARNING  path entry '/usr/share/python-support/pgloader/reformat' does not exists, ignored
pgloader     INFO     Reformat path is []
pgloader     INFO     Will consider following sections:
pgloader     INFO       csv
csv          INFO     csv processing
csv          INFO     TRUNCATE TABLE pgloader_table;
pgloader     INFO     All threads are started, wait for them to terminate
csv          INFO     COPY 1: 20000 rows copied in 1.651s
csv          INFO     COPY 2: 20000 rows copied in 1.752s
csv          INFO     COPY 3: 20000 rows copied in 1.809s
csv          INFO     COPY 4: 20000 rows copied in 1.815s
csv          INFO     COPY 5: 20000 rows copied in 1.736s
csv          INFO     COPY 6: 20000 rows copied in 1.738s
csv          INFO     COPY 7: 20000 rows copied in 1.710s
csv          INFO     COPY 8: 20000 rows copied in 1.618s
csv          INFO     COPY 9: 20000 rows copied in 1.611s
csv          INFO     COPY 10: 20000 rows copied in 1.624s
csv          INFO     COPY 11: 19173 rows copied in 1.535s
csv          INFO     No data were rejected
csv          INFO      219173 rows copied in 11 commits took 18.761 seconds
csv          INFO     No database error occured
csv          INFO     closing current database connection
csv          INFO     releasing csv semaphore
csv          INFO     Announce it's over

Table name        |    duration |    size |  copy rows |     errors 
====================================================================
csv               |     18.757s |       - |     219173 |          0


Jak to działa po stronie PostgreSQL?

Program dzieli dane na części (wielkość każdej części jest uzależniona od parametry copy_every), ustawia połączenie z baza danych, wykonuje zapytanie COPY:

COPY pgloader_table (KOLUMNY, ...)  FROM STDOUT WITH DELIMITER ',';

i na standardowe wyście wysyła dane. Jeśli chcieli byśmy wykonać to ręcznie to odbyło by się to następująco:

127.0.0.1:7432 postgres@pgloader # COPY test_copy (c2,c3) FROM STDOUT WITH DELIMITER ',';
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.
>> cos tam 1,2
>> cos tam 2,3
>> cos tam 4,4
>> cos tam 5,25
>> \.
Time: 52529,504 ms
127.0.0.1:7432 postgres@pgloader # select * from test_copy;
+----+-----------+----+
| id |    c2     | c3 |
+----+-----------+----+
|  1 | cos tam 1 |  2 |
|  2 | cos tam 2 |  3 |
|  3 | cos tam 4 |  4 |
|  4 | cos tam 5 | 25 |
+----+-----------+----+
(4 rows)

Time: 0,337 ms

Do pustej tabeli test_copy importuje 4 wiersze. Dane do kolumn są oddzielone przecinkiem. Po wykonaniu komendy COPY PostgreSQL informuje nas:
Enter data to be copied followed by a newline.
End with a backslash and a period on a line by itself.


Ciekawostka!

Jeśli się zastanawiacie jak to możliwe, że pgloader używa polecenia COPY w ten sposób skoro w według dokumentacji (http://www.postgresql.org/docs/9.1/static/sql-copy.html) polecenie COPY ma konstrukcje:

COPY table_name [ ( column [, ...] ) ]
    FROM { 'filename' | STDIN }
    [ [ WITH ] ( option [, ...] ) ]

COPY { table_name [ ( column [, ...] ) ] | ( query ) }
    TO { 'filename' | STDOUT }
    [ [ WITH ] ( option [, ...] ) ]
to zaznaczę od razu, że dozwolona jest kombinacja FROM/TO i STDIN/STDOUT (mimo iż dokumentacja na to nie wskazuję!). Aby wyjaśnić troszkę tą nieścisłość i może niedowierzanie, kieruje was do posta z listy "pgsql-hackers": Re: "COPY foo FROM STDOUT" and ecpg.


PGLoader będzie szczególnie przydatne gdy chcecie zaimportować dane a nie macie praw dostępu administratora do serwera - aby zaimportować dane z pliku przy pomocy polecenia COPY, wymagane jest przekopiowanie go na serwer. Narzędzie dodatkowo formatuje nasze dane i informuje o błędach bez przerywania importu danych poprawnych (ale opcja --pedantic wymusi zatrzymanie procesowania w razie wystąpienia warningów).