świat się kończy – apple sprzedaje tanie komputery

tanie, to może za dużo powiedziane. ale “tańsze"  – już nie.

ed burnette z zdnet'u porównał ceny laptopów: apple i dell. najpierw takie mocno “wypasione" a potem wersje tańsze, prostsze.

starał się dobrać maksymalnie zbliżone konfiguracje – oczywiście idealnie takich samych się nie da.

wynik?

w segmencie high-end apple za $2699 sprzedaje to co dell za $3222. różnica w cenie: $523. za ten pieniądze dell dorzuca lepszą rozdzielczość, wifi obsługujące 802.11a i gwarancję w domu.

802.11a mnie nie obchodzi. gwarancja w domu. no cóż. niby miłe, ale akurat mam pewnie doświadczenia z serwisem della, więc powiem tylko: to nie jest tak piękne jak na to wygląda. wyższa rozdzielczość natomiast to zdecydowany plus.

natomiast apple mimo niższej ceny też dał radę wstawić coś czego konkurencja nie dała: kamerę do wideokonferencji, podświetloną klawiaturę, dłuższy support (90 zamiast 30 dni) oraz fakt iż ich laptop jest mniejszy i lżejszy.

kamera – fajna. przyda się może jak będę miał więcej znajomych z kamerami. podświetlana klawiatura – mogę żyć bez tego – na klawisze i tak nie patrzę. support – obym nie potrzebował. ale fakt, że jest lżejszy mocno do mnie przemawia.

potem było porównanie lapów tańszych.

tym razem dell zaproponował rozwiązanie o niższej cenie: $1037, a apple o ciut ($187) wyższej: $1224.

i znowu są pewne rzeczy dodawane. w dellu dorzucili więcej portów usb (4 zamiast dwóch). sorry, ale jakoś mnie to nie wzrusza. korzystam z jednego – maksymalnie dwóch.

apple natomiast za te 187 dolarów dorzucił: kamerę, dłuższy support, oraz znowu – lap jest mniejszy i lżejszy.

i muszę przyznać, że oferta apple'a wygląda zdecydowanie lepiej. nie lubię tej firmy. uważam ich taktyki, zagrania i sposób postępowania z ludźmi za fatalny. maci ogólnie uważam za pomyłkę i dno. ale nie zmienia to faktu, że dają więcej w tej samej cenie, lub tyle samo za mniejszą cenę. czyli są lepszym wyborem. nawet jeśli docelowo będziemy na tym używać windowsa czy linuksa.

nowości w postgresie 8.2 – … nieblokujące tworzenie indeksów

ta poprawka mnie osobiście ratuje życie, ale mam świadomość, że tyczy się relatywnie niewielkiej ilości osób.

tworzenie indeksu (create index, create unique index) jest operacją blokującą.

w czasie tworzenia wszelkie operacje insert/update/delete na tabeli na której jest robiony indeks są wstrzymane.

zazwyczaj nie jest to problem – create index trwa np. kilka sekund. ale pojawia się problem co z większymi bazami, np. serwisami aukcyjnymi. tabele są spore, ruch jest non stop. jeśli np. zakładałbym indeks na tabeli “aukcje" w której jest kilkadziesiąt milionów rekordów, to tworzenie indeksu może spokojnie potrwać kilkanaście minut.

a w tym czasie wszystkie insert/update/delete by były wstrzymane. co oznacza, że jak ktoś będzie chciał dodać nową aukcję, to będzie czekał, czekał, a po 3 minutach przeglądarka go rozłączy i wyświetli komunikat o time-out'cie. cienko. rzekłbym nawet, że fatalnie.

czy nic nie da się zrobić? wcześniej – nie dawało sie. ale teraz jest lekarstwo:

# CREATE INDEX CONCURRENTLY ble ON tabelka (pole);
# CREATE UNIQUE INDEX CONCURRENTLY ble_u ON tabelka (pole, inne_pole);

indeksy tworzone z klauzulą CONCURRENTLY nie blokują zapisów! czyli wszystko działa tip-top.

haczyki? zawsze są. najważniejszy jest taki, że tworzenie indeksów w ten sposób jest wolniejsze. ale to za bardzo nie przeszkadza.

z innych rzeczy:

  • polecenie reindex nie porafi użyć “concurrently"
  • jeśli create index concurrently się wywali – w systemie zostanie tworzony indeks zawieszony w dziwnym stanie – niby jest, ale system z niego nie korzysta – przed ponowieniem próby założenia tego indeksu trzeba go skasować.
  • jeśli tworzymy indeks typu UNIQUE, to warunki unikalności są sprawdzane w trakcie tworzenia indeksu (dokładniej to w czasie drugiej fazy tworzenia indeksu). dzieje się tak mimo faktu iż nieistniejący jeszcze indeks nie może być użyty do wyszukiwania. jeśli w trakcie tworzenia indeksu polecenie create unique indeks wykryje powtarzające sie wartości – wywali się – i tu trzeba będzie skasować popsuty indeks (vide punkt wyżej)
  • można robić nieblokująco zarówno indeksy zwykłe jak i wielopolowe, funkcyjne czy częściowe.
  • można robić jednocześnie wiele indeksów w sposób nieblokujący, z tym, że nie więcej niż jeden na tabelę.
  • zwykły create index może być użyty w transakcji, ale create index concurrently – już nie.
  • tak samo jak przy zwykłych indeksach, tak samo przy tworzeniu nieblokującym nie są dopuszczone zmiany definicji tabeli na której tworzymy indeks

jak widać jest to funkcjonalność lekko (w/g mnie) jeszcze niewygładzona, ale zakładam, że rzeczy typu – pozostający “cień indeksu" po błędnym indeksowaniu – zostaną wyeliminowane dosyć szybko.

a poza tym – fenomenalna funkcjonalność. od zawsze mi jej brakowało.

czy pisuar może być ładny?

zapewne większości moich czytelników zdarzyło się kiedyś korzystać z pisuaru. lotniska, dworce, restauracje, centra handlowe.

czy zastanowiliście się kiedyś czy da się zrobić pisuar ładny? pewnie nie. nie tylko wy – większość ludzi o tym nie myśli. ale kilka osób tak. dzięki pomysłom tych ludzi mamy prawdziwe dzieła sztuki – nawet jeśli jedyną sztuką jaką zobaczą będzie trafienie do środka po kilku (nastu) piwach.

“capture the flag” – w rzeczywistości.

kanadyjczycy zorganizowali sobie sesję “capture the flag" w toronto. w zabawie wzięło udział 1200 osób (z czego kilka co widać na filmiku nie za bardzo wiedziało o co chodzi:)

dla tych co nie wiedzą to co jest capture the flag.

dwa zespoły ukrywają na swoim terenie flagi. cel jest prosty – znaleźć flagę przeciwnika, przechwycić i dostarczyć do swojej bazy.

do tego dochodzą dodatkowe reguły, ale one są tylko po to by nie było za łatwo, no i aby nie dochodziło do scysji.

ctf pochodzi z gier komputerowych – dokładniej z jednego z dodatków do quake'a. o tym, że ktoś w to gra w świecie poza-komputerowym nie słyszałem, ale skala zabawy w kanadzie sugeruje, że ktoś gdzieś kiedyś pewnie grał w mniejszej grupie 🙂 ogólnie – kawałek fajnej zabawy.

czym się zajmuje microsoft?

ostatnio wszyscy jakoś zapomnieli, że microsoft ma wielki dział r&d.

nowe produkty i usługi stały się domeną malutkich firm (wykupywanych potem przez google'a i yahoo) albo google'a i yahoo.

a microsoft? oni nadal tam są. mają kasę i przeznaczają sporą jej część na badania i rozwój.

jeden z managerów r&d podzielił się ostatnio z informationweek‘iem informacjami o najlepiej rokujących projektach z ogólnie pojętego “bezpieczeństwa komputerowego":

  • ghostbuster – zaawansowany program wykrywający rootkity. najprawdopodobniej będzie oddzielnym produktem i nie zostanie włączony w windows.
  • shield – rodzaj firewalla, z tym, że pracujący na danych warstwy aplikacji, chroniący przez błędami. jak rozumiem działa to tak, że shield pobiera listę problemów (vulnerabilities) i odpowiednio chroni system przez programami wykorzystującymi te błędy.
  • suremail – potencjalne rozwiązanie rzadkiego problemu 🙂 panowie estymują, że 1% maili ginie bezpowrotnie w systemach pocztowych. suremail ma być mechanizmem pozwalającym programowi pocztowemu nadawcy wiedzieć czy mail faktycznie dotarł do inboxa odbiorcy
  • vigilante – program służący do wykrywania ataków typu zero-day poprzez analizę ruchu i honey-poty
  • xfi – rozszerzenie istniejących mechanizmów pozwalające w bezpieczniejszy sposób uruchamiać programy/kod ściągnięte z sieci – takie jak np. plugin'y, kodeki i inne.
  • soft wykrywający phishing poprzez sprawdzanie do jakich serwisów są wysyłane (http/post) dane i w przypadku sytuacji anormalnych – alertowanie

jak widać panowie z redmond nie próżnują i ciężko pracują. czy wreszcie na windows będzie bezpieczniej? oby.

sofa – pogromca supermana?

przeczytałem ostatnio o interesującym … materiale. tak. mam na myśli takie coś z czego robi się obicia do sof/foteli/krzeseł/czegokolwiek.

co w nim fajnego? jest zrobiony z użyciem jakichś tam psiejsko-czarodziejskich technologii. i nie daje się pobrudzić. nie przyczepiają się do niego włosy zwierzaków, zmycie plam – w tym tych po winie czy kredkach – jest trywialne, nie trzymają się go brzydkie zapachy. po prostu cud dla każdej osoby mającej w domu zwierzątko futrzane (koty, psy) czy dzieci które brudzą (czyli zasadniczo każdy rodzic).

materiał nazywa się “crypton" (stąd tytuł postu) i jest dostępny z tego co wyczytałem na razie tylko w stanach.

jeśli chodzi o cenę – no cóż. nie mam porównania w ogóle do cen materiałów w polsce, ale 1 jard (około 110 centymetrów) z beli o szerokości 54 cali (137 cm) kosztuje $52 (plus transport). oczywiście materiał jest dostępny w szerokiej gamie kolorów, wzorów itd, itd.

na stronie materiału/producenta można pooglądać, poczytać, kupić a także zobaczyć krótki film (w cienkiej jakości niestety) pokazujący jak to działa.

no cóż. chyba zacznę zbierać kasę. dzieci mam. futrzaków nie, ale sam też czasem coś rozleję czy zaplamię.

nowości w postgresie 8.2 – … aliasy w update/delete

to akurat poprawka malutka, ale jak dla mnie po prostu bogosławiona.

jak może wiecie polecenie update (a także delete) może aktualizować dane z pomocą innej tabeli. przykładowo:

# CREATE TABLE statusy (id serial PRIMARY KEY, kod TEXT);
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "statusy_id_seq" FOR serial COLUMN "statusy.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "statusy_pkey" FOR TABLE "statusy"
CREATE TABLE
# INSERT INTO statusy (kod) VALUES ('new'), ('open'), ('resolved'), ('rejected');
INSERT 0 4
# CREATE TABLE zgloszenia (id serial, temat TEXT, status_id INT NOT NULL REFERENCES statusy (id));
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "zgloszenia_id_seq" FOR serial COLUMN "zgloszenia.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "zgloszenia_pkey" FOR TABLE "zgloszenia"
CREATE TABLE
# INSERT INTO zgloszenia (temat, status_id) VALUES ('a', 1), ('b', 2), ('c', 3), ('d', 4);
INSERT 0 4
# ALTER TABLE zgloszenia ADD COLUMN STATUS TEXT;
ALTER TABLE
# UPDATE zgloszenia SET STATUS = s.kod FROM statusy s WHERE s.id = status_id;
UPDATE 4
# SELECT * FROM zgloszenia;
id temat status_id status

(4 rows)

fajne. ale – jeśli nazwy kolumn się powtarzają (np. ja mam w każdej tabeli pole “id" będące primary key'em) to trzeba postgresowi powiedzieć o które pole dokładnie mi chodzi. póki używam id z tabel dołączanych to nie problem – w “FROM" mogę podać alias na tabelę (w przykładzie powyżej: “s"). ale już tabeli którą aktualizuję – nie mogłem aliasować.

teraz już mogę. dzięki czemu nawet przy aktualizowaniu tabeli o długiej nazwie i używaniu w warunkach jej pól nie będę miał kosmicznie długiego sql'a – trudnego do czytania i poprawiania.

wygląda to na przykład tak:

UPDATE wynagrodzenia_pracownikow s SET pensje = SUM(p.wynagrodzenie) FROM wynagrodzenia_pracownikow p WHERE p.przelozony_id = s.id;

ten sam mechanizm działa w przypadku delete'ów join-ujących tabele w celu stworzenia odpowiednich warunków.

nowości w postgresie 8.2 – … values

post zaległy od wczoraj 🙂

w czasie projektowania i proponowania nowości do postgresa 8.2 padła idea by zacząć obsługiwać inserty wstawiające wiele rekordów. tak jak ma np. mysql:

INSERT INTO `tabele` (`pole1`, `pole2`) VALUES (1,1),(2,4),(2,7);

jak zawsze – panowie z core-teamu stwierdzili, że skoro robią już coś takiego, to może to trochę podkręcić.

wyszło z tego zupełnie nowe polecenie sql'owe: VALUES.

dzięki temu mogli zachować kompatybilność z standardowymi sql'ami, ale także wykorzystać to dla innych zastosowań.

zacznijmy od podstaw:

# CREATE TABLE x (id serial PRIMARY KEY, p_a TEXT, p_b TEXT);
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "x_id_seq" FOR serial COLUMN "x.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "x_pkey" FOR TABLE "x"
CREATE TABLE
# INSERT INTO x (p_a, p_b) VALUES ('standardowa', 'metoda');
INSERT 0 1
# INSERT INTO x (p_a, p_b) VALUES ('nowsza', 'metoda'), ('drugi', 'rekord'), ('następne', 'rekordy');
INSERT 0 3
# SELECT * FROM x;
id p_a p_b

(4 rows)

fajne. tylko po co? no cóż. zrobiłem mały test. zrobiłem tabelkę:

# CREATE TABLE x (id serial PRIMARY KEY, liczba INT4);

i wstawiałem do niej dane (100000 kolejnych liczb) na kilka sposobów:

  • copy x (liczba) from stdin;
  • 100000 insertów – każdy po jednym rekordzie
  • 100000 insertów – każdy po jednym rekordzie (ale z użyciem prepare i execute)
  • 10000 insertów – każdy po dziesięć rekordów
  • 10000 insertów – każdy po dziesięć rekordów (ale z użyciem prepare i execute)
  • 5000 insertów – każdy po dwadzieścia rekordów
  • 5000 insertów – każdy po dwadzieścia rekordów (ale z użyciem prepare i execute)

wyniki:

  • copy: 0m1.045s
  • insert (1): 1m5.473s
  • insert + prepare (1): 1m3.483s
  • insert (10): 0m8.500s
  • insert + prepare (10): 0m7.552s
  • insert (20): 0m4.065s
  • insert + prepare (20): 0m3.656s

dla chętnych do powtórzenia testów/obejrzenia – skrypty oczywiście są dostępne.

graficznie wygląda to jeszcze bardziej interesująco:

chart-values.pngjak widac przyspieszenie insertów jest znaczne. czy to wszystko? nie!

values można wykorzystać wszędzie tam gdzie potrzebujemy wielu rekordów. przykładowe zastosowanie – wyobraźmy sobie, że mamy pole typu int z zapisanymi statusami. statusów jest ledwie kilka. nie warto dla nich robić oddzielnej tabeli. ale jednak chcielibyśmy móc je w jakiś sposób odczytać z bazy … proszę:

# CREATE TABLE x (id serial PRIMARY KEY, liczba INT4);
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "x_id_seq" FOR serial COLUMN "x.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "x_pkey" FOR TABLE "x"
CREATE TABLE
# INSERT INTO x (liczba) VALUES (1), (2), (3), (2);
INSERT 0 4
# SELECT
x.id, x.liczba, k.kod
FROM x
JOIN (VALUES (1, 'closed'), (2, 'new'), (3, 'open')) AS k (id, kod) ON x.liczba = k.id
;
id liczba kod

(4 rows)

oczywiście powyższy efekt można uzyskać używając (CASE WHEN … END), ale to rozwiązanie jest krótsze i mocno czytelniejsze.

zwracam też uwagę na to, że w oparciu o VALUES można zdefiniować widok:

# CREATE VIEW statusy AS SELECT * FROM (VALUES (1, 'closed'), (2, 'new'), (3, 'open')) AS k (id, kod);
CREATE VIEW
# SELECT * FROM statusy;
id kod

(3 rows)

co jeszcze można z tym zrobić? sporo. pobawcie się sami i zastanówcie do czego można tego użyć.