jak może wiecie wordpress od zawsze był na mysql'u.
dodatkowo – team wordpressa nigdy nie wykazał się chęcią modyfikacji kodu aby działał na innych platformach bazodanowych – w szczególności na postgresie. a byli pytani/proszeni przez ludzi z okolic core-teamu postgresa!
ostatnio przeczytałem na blogu drixtera, że aure zrobił nieoficjalny port wordpressa na postgresa. i to nie jakąś prehistoryczną wersję tylko 2.0.4! tak więc – zachęcam do testowania 🙂
Tag: postgresql
tsearch poza contribem. w core’rze
rosyjski team (oleg i teodor) przysłał pierwszą wersję patcha przenoszącego tsearcha do podstawowego postgresa.
zmiana nie jest wielka – funkcjonalność pozostaje ta sama, ale przyjemniej się teraz konfiguruje, używa – no i nie trzeba sprawdzać czy contriby są poinstalowane 🙂
zmiany:
- tabele pg_ts_* są teraz w schemie pg_catalog. wreszcie!
- parsery, słowniki i konfiguracje są teraz częścią systemu postgresa – tak jak tabele, klasy operatorów itd. dzięki czemu są przyporządkowane do schemy – można mieć różne w różnych schemach – np. wybór różnych parserów przez autodetekcję locale – zależny od schemy!
- wybór aktualnej konfiguracji tsearcha odbywa się przez ustawienie zmiennej postgresa (czyli tak jak np. shared_buffers czy inne)
- zarządzanie konfiguracją tsearcha odbywa się teraz z użyciem poleceń sql'a (create i pochodne) a nie wyrażeń insert/update/delete. pozwala to na lepszą obsługę dumpów, tworzenia, kasowania i zarządzania zależnościami
- psql umożliwi wyświetlanie konfiguracji systemu fts poprzez polecenia \d* (\dF dokładniej)
- dodane z automatu wszystkie dostępne stemmery snowball'owe, oraz ich odpowiednie konfiguracje
- poprawki związane ze zwalnianiem pamięci
ogólnie – krok w dobrą stronę.
patch jest na razie w wersji alfa, ale myślę, że do 8.3 wejdzie na pewno.
można już się zapoznać z aktualizowaną na bieżąco dokumentacją – na razie na stronach olega i teodora, ale już niedługo w standardowych doc'ach postgresa.
aha. informacyjnie – prace nad wdrożeniem tsearcha do core'a są sponsorowane przez enterprisedb – producenta wersji postgresql'a zmodyfikowanej w celu zachowania wiekszej kompatybilnosci z oracle'em.
enum
na grupie pgsql-patches trwa dyskusja nad nową wersją patcha dodającego enumy.
jest kilka argumentów przeciwko enumom jako takim, kilka przeciwko temu konkretnie patchowi i całkiem sporo za tym aby enumy tym patchem włączyć do postgresa!.
wszystko wskazuje na to, że w nowym postgresie (8.3?) będzie można:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
CREATE TABLE person (
name text,
current_mood mood
);
INSERT INTO person VALUES ('Moe', 'happy');
SELECT * FROM person WHERE current_mood = 'happy';
name | current_mood
------+--------------
Moe | happy
(1 row)
fajnie 🙂
jak dodać kolumnę do tabeli
teoretycznie dodanie kolumny do tabeli nie jest problemem. od daaaaaaaaaaaaaawna istnieje ALTER TABLE ADD COLUMN. czy jednak jest to zawsze bezproblemowe?
niestety nie.
otóż – dodanie pola do tabeli zakłada na nią (w całości) exclusive locka.
dla standardowego:
ALTER TABLE t ADD COLUMN c INT8;
to nie problem – taki ALTER trwa moment.
ale co jeśli robimy:
ALTER TABLE t ADD COLUMN c INT8 NOT NULL DEFAULT 123;
tu pojawia się problem.
po pierwsze – not null – wymusza sprawdzenie zawartości bazy.
po drugie – ważniejsze – wyspecyfikowanie "default" przy dodawaniu pola automatycznie wstawi wartość domyślną do wszystkich rekordów obecnie w tabeli.
zasadniczo – super. o to chodzi. ale jak sobie nałożymy na to fakt iż ALTER TABLE lockuje tabelę – oops. recepta na kłopoty.
w szczególności – mając tabelę typu kilka milionów rekordów, na której non stop ktoś pracuje (np. dosyć aktywny serwis www) – zrobienie na niej takiego ALTERa to realnie sprawę ujmując wyłączenie ta
beli i serwisu.
jak więc zrobić dodanie z wyspecyfikowaniem w sposób słuszny?
no cóż – trzeba robić to krokami:
po pierwsze:
ALTER TABLE t ADD COLUMN c INT8;
to się wykona błyskawicznie.
potem (ale jako oddzielne zapytanie!):
ALTER TABLE t ALTER COLUMN c SET DEFAULT 123;
to też pójdzie szybko bo niczego nam nie zaktualizuje. po prostu – nowo wstawiane rekordy będą miały defaulta.
teraz – trzeba zaktualizować starsze. najprościej:
UPDATE t SET c = 123 WHERE c IS NULL;
w szczególności – jak danych jest więcej niż mało (powiedzmy powyżej 100,000 rekordów), to warto rozbić to na kilka oddzielnych zapytań. np:
UPDATE t SET c = 123 WHERE c IS NULL AND id BETWEEN 1 AND 100000;
UPDATE t SET c = 123 WHERE c IS NULL AND id BETWEEN 100001 AND 200000;
itd.
oczywiście – nie można do tego celu użyć funkcji – cała idea tego rozbijania polega na tym by nie robić tego wszystkiego w jednej, olbrzymiej, transakcji!.
no i na koniec pozostaje:
ALTER TABLE t ALTER COLUMN c SET NOT NULL;
to chwilę potrwa – postgres musi sprawdzić dane, ale i tak jest to krótsze i mniej blokujęce niż robienie wszystkiego za jednym zamachem.
oczywiście w tej chwili ktoś może się odezwać i powiedzieć, że w bazie <xxx> to jest prostsze, nie trzeba nic rozbijać, bla bla bla. fakt. w postgresie też nie trzeba – to co pokazałem to jedynie hint jak obejść blokadę przy dodawaniu pól z wartościami domyślnymi przy sporych tabelkach. można to zrobić jednym zapytaniem. i też zadziała. po prostu czasem nie chcemy/nie możemy mieć locka na taki czas jaki jest potrzebny ALTERowi 🙂
tsearch i synonimy
od daaaaawna w postgresie jest dostępny świetny silnik wyszukiwania pełnotekstowego – tsearch.
ma on spore możliwości, ale jest dosyć trudny przy pierwszym podejściu – trzeba poświęcić z pół godziny na to by załapać o co chodzi, skonfigurować i używać.
natomiast jak już się zrozumie co i jak – można prosto robić nowe, ciekawe rzeczy. przykładowo – dodać własne słowniki synonimów. dokładną metodę zrobienia takiego słownika i dodania go do systemu wyszukującego przedstawił w swoim blogu magnus hagander – ja to przeczytałem i polecam każdemu kto chce zobaczyć jak zrobić ciekawe rzeczy w postgresie.
currval i problemy z selectami
jak może wiecie w postgresie jest funkcja currval() zwracająca ostatnio nadane id z podanej sekwencji.
rozpatrzmy prosty przypadek:
# CREATE TABLE test (id serial PRIMARY KEY, pole int4); CREATE TABLE # INSERT INTO test (pole) SELECT * FROM generate_series(1, 10000); INSERT 0 10000 # SELECT COUNT(*) FROM test; COUNT ------- 10000 (1 ROW) # SELECT currval('test_id_seq'); currval --------- 10000 (1 ROW)
wszystko wygląda ok. więc sprawdźmy jeszcze jeden insert mały:
# INSERT INTO test(pole) VALUES (12313); INSERT 0 1 # SELECT currval('test_id_seq'); currval --------- 10001 (1 ROW)
nadal wszystko ok. i teraz:
# SELECT * FROM test WHERE id = currval('test_id_seq'); id | pole -------+------- 10001 | 12313 (1 ROW) TIME: 93.358 ms
działa, ale coś wolno, sprawdźmy:
# EXPLAIN analyze SELECT * FROM test WHERE id = currval('test_id_seq'); QUERY PLAN -------------------------------------------------------------------------------------------------- Seq Scan ON test (cost=0.00..200.02 ROWS=1 width=8) (actual TIME=64.375..64.379 ROWS=1 loops=1) FILTER: (id = currval('test_id_seq'::regclass)) Total runtime: 64.431 ms (3 ROWS)
seq scan? sprawdźmy więc ręcznie podaną wartość:
# EXPLAIN analyze SELECT * FROM test WHERE id = 10001; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- INDEX Scan USING test_pkey ON test (cost=0.00..8.02 ROWS=1 width=8) (actual TIME=0.029..0.033 ROWS=1 loops=1) INDEX Cond: (id = 10001) Total runtime: 0.086 ms (3 ROWS)
hmm .. tu jest dobrze. skąd seq scan? aby nie przynudzać z każdym zapytaniem, powiem tyle, że nie jest to kwestia błędnych typów czy czegoś tak oczywistego. problemem jest zmienność funkcji.
dokładniej: funkcja currval() jest zadeklarowana jako “volatile" – co oznacza, że jej wynik ma prawo zmienić się w czasie pojedynczego skanu tabeli. tak jak np. random(). to oznacza, że nie można użyć jej jako dostarczyciela wartości i potem tą wartością przeszukać indeksy.
cóż więc można zrobić – no cóż. trzeba powiedzieć postgresowi, że interesuje nas tylko pierwsza zwrócona wartość currvala – idealnie do tego nadają się podzapytania:
# EXPLAIN analyze SELECT * FROM test WHERE id = (SELECT currval('test_id_seq')); QUERY PLAN ---------------------------------------------------------------------------------------------------------------- INDEX Scan USING test_pkey ON test (cost=0.01..8.03 ROWS=1 width=8) (actual TIME=0.047..0.050 ROWS=1 loops=1) INDEX Cond: (id = $0) InitPlan -> RESULT (cost=0.00..0.01 ROWS=1 width=0) (actual TIME=0.010..0.012 ROWS=1 loops=1) Total runtime: 0.187 ms (5 ROWS)
jak widać jest już zdecydowanie lepiej.
ile jest wart postgres
dziś jest dzień postgresql'owy, więc kolejna informacja o nim.
jest taki program: sloccount. służy do liczenia ilości linii kodu, oraz estymowaniu kosztów stworzenia programu.
odpaliłem go na źródłach postgresa 8.2. oto wynik:
Totals grouped by language (dominant language first): ansic: 479298 (94.01%) yacc: 14698 (2.88%) sh: 7805 (1.53%) lex: 5349 (1.05%) perl: 2608 (0.51%) asm: 65 (0.01%) python: 12 (0.00%) <br/> Total Physical Source Lines of Code (SLOC) = 509,835 Development Effort Estimate, Person-Years (Person-Months) = 139.26 (1,671.14) (Basic COCOMO model, Person-Months = 2.4 * (KSLOC**1.05)) Schedule Estimate, Years (Months) = 3.50 (41.95) (Basic COCOMO model, Months = 2.5 * (person-months**0.38)) Estimated Average Number of Developers (Effort/Schedule) = 39.84 Total Estimated Cost to Develop = $ 18,812,337 (average salary = $56,286/year, overhead = 2.40). SLOCCount, Copyright (C) 2001-2004 David A. Wheeler SLOCCount is Open Source Software/Free Software, licensed under the GNU GPL. SLOCCount comes with ABSOLUTELY NO WARRANTY, and you are welcome to redistribute it under certain conditions as specified by the GNU GPL license; see the documentation for details. Please credit this data as "generated using David A. Wheeler's 'SLOCCount'."
pl/scheme
(hurra, (dzięki (projektowi (pl/scheme))) (wreszcie) (będziemy (się (mogli))) (w postgresie) (cieszyć (z kodu (składającego się (z samych (nawiasów)))))) 🙂
funkcje ułatwiające migracje z oracle’a
przeczytałem właśnie o interesującym module – orafce. moduł ten zawiera ponad 100 funkcji których celem jest emulowanie funkcji bazodanowych z oracle'a i plvision (taki pakiet do oracle'a).
funkcje w orafce są kompatybilne na poziomie api z wersjami z oracle'a co powoduje, że ich użycie mocno uprości ewentualną migrację między tymi platformami.
wśród funkcji zawartych w pakiecie są m.in.:
- kilka funkcji podstawowych – typu next_day, last_day
- funkcje kalendarza biznesowego – bazujące na pakiecie plvdate z plvision
- spory zestaw funkcji do pracy na stringach
- obsługa komunikacji między procesowej
zwrócić należy uwagę na fakt iż nie ma w tym pakiecie niczego czego nie dałoby się uzyskać w postgresie inaczej – jednakże sensem istnienia tego pakietu nie jest dodawanie funkcjonalności, a ułatwianie migracji.
nowości w postgresie 8.2 – … advisory locks
miałem o tym napisać później, ale skoro merlin już opisał advisory locki, nie pozostaje mi nic innego niż
opisać je u siebie.
advisory locki są to zupełnie nowe locki nie powiązane z żadnymi fizycznymi obiektami w bazie. służą one do
przekazywania informacji między sesjami i transakcjami.
najbardziej szczególną cechą tych locków jest to, że działają poza mechanizmem transakcji. dzięki temu możliwe jest używanie
ich do celów do których standardowe locki sie nie nadawały.
przykładem użycia z mojego podwórka jest zakładanie locka na konkretne źródło rss'ów w dnewsach. do tej pory musiałem mieć
oddzielną tabelkę i w niej trzymać wpisy. do tego dochodziły kwestie czyszczenia wpisów gdyby program ściągający dane padł i nie
skasował swojego locka.
z drugiej strony – mogłem uzyć locków wewnątrz transakcji, ale to by oznaczało trzymanie długo trwających transakcji – a one z
definicji są złe (psują systemy replikacyjne).
advisory locki robią to co trzeba.
sesja (połącznie) które potrzebuje zakłada locka (locka zakłada sie na “liczbę" z zakresu int8, albo na parę liczb int4). lock
zostaje zdjęty gdy wywołam funkcję zdejmującą lub gdy padnie połączenie!
advisory locki są trzymane w pamięci dzięki czemu są baaaaaardzo szybkie – merlin przeprowadził prosty test zakładając 1000
advisory locków w około 6 milisekund!
dodatkowo – dzięki temu, że są trzymane w pamięci – odpadaję wszelkie bolączki mvcc – puchnące tabele, wolny odczyt,
vacuumowanie itd. advisory locki są błyskawiczne i całkowicie bezpieczne.
przykładowe użycie:
# SELECT pg_advisory_lock(123);<br/> pg_advisory_lock<br/> ------------------<br/> ''<br/> (1 ROW)<br/> # SELECT pg_advisory_unlock(123);<br/> pg_advisory_unlock<br/> --------------------<br/> t<br/> (1 ROW)
oczywiście advisory locki zapewniają wszystkie standardowe metody dostępu:
- pobranie locka blokujące
- pobranie nieblokujące
- locki exclusive
- locki shared
polecam przyjrzenie
się tej funkcjonalności – ma ona sporo niecałkiem oczywistych zastosowań.