Krzysztof Raczkowski

Krzysztof Raczkowski Stała współpraca,
Logifact-Systems Sp.
z o.o.

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Taki trochę cross-post... ale temat nie tylko o MS SQL.. a może ktoś nie zapisany jest do obydwóch :)

http://www.goldenline.pl/forum/3123272/ms-sql-lub-post...

--
Pozdrawiam
K. R.

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Odpowiem tutaj, bo to odpowiedź nie biorąca pod uwagę kruczki i sztuczki konkretnego DBMS.

Nawet jeśli rozbijesz to pole na kilka pól (jedna flaga per pole) to z uwagi na to że w polu będziesz miał tylko dwie wartości może się zdarzyć że indeks nie będzie używany.

Zamiast tego możesz spróbować z tablicami:


create table flagi_danych_0 {
tabela_dane_pk_id int not null,
CONSTRAINT pk_flagi_danych_0 PRIMARY KEY (tabela_dane_pk_id)
}

create table flagi_danych_1 {
tabela_dane_pk_id int not null,
CONSTRAINT pk_flagi_danych_1 PRIMARY KEY (tabela_dane_pk_id)
}

...

create table flagi_danych_n {
tabela_dane_pk_id int not null,
CONSTRAINT pk_flagi_danych_n PRIMARY KEY (tabela_dane_pk_id)
}

select t1.pk_id, pole1, pole2 from tabela_dane t1
inner join flagi_danych_12 f12 on (t1.pk_id = f12.tabela_dane_pk_id)


Czyli jedna tabela per flaga. Wtedy indeks musi być użyty (unikalny, PK).Piotr L. edytował(a) ten post dnia 10.12.12 o godzinie 08:39

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

W Postgresie pokombinowałbym z indeksami częściowymi, coś jak:


CREATE INDEX i_12 ON tab (id) WHERE flag & 12 = 12;


Wtedy będzie użyty w takim zapytaniu jak:


SELECT * FROM tab WHERE flag & 12 = 12;


Taki indeks przechowuje informacje tylko o pasujących wierszach, więc będzie względnie mały.

Bardziej uniwersalne byłoby zrobienie indeksów dla poszczególnych bitów:


CREATE INDEX i_b_1 ON flag_test(id) WHERE flag&1 = 1;
CREATE INDEX i_b_2 ON flag_test(id) WHERE flag&2 = 2;
CREATE INDEX i_b_4 ON flag_test(id) WHERE flag&4 = 4;
CREATE INDEX i_b_8 ON flag_test(id) WHERE flag&8 = 8;
CREATE INDEX i_b_16 ON flag_test(id) WHERE flag&16 = 16;
CREATE INDEX i_b_32 ON flag_test(id) WHERE flag&32 = 32;


I wtedy zapytanie robisz tak:


SELECT * FROM tab WHERE flag & 4 = 4 and flag & 8 = 8;

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Szymon G.:
I wtedy zapytanie robisz tak:


SELECT * FROM tab WHERE flag & 4 = 4 and flag & 8 = 8;

Tylko tu są dwa pytania:
a) czy DBMS użyje dwóch indeksów do jednej tablicy
b) czy indeks będzie użyty niezależnie od rozkładu wartości (np. 40% ma flagę 4 = 1 => użyje czy nie?)

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Piotr L.:
Szymon G.:
I wtedy zapytanie robisz tak:


SELECT * FROM tab WHERE flag & 4 = 4 and flag & 8 = 8;

Tylko tu są dwa pytania:
a) czy DBMS użyje dwóch indeksów do jednej tablicy
b) czy indeks będzie użyty niezależnie od rozkładu wartości (np. 40% ma flagę 4 = 1 => użyje czy nie?)

Plan zależy bardzo od rozkładu wartości. Teoretycznie Postgres używa jak najbardziej tych różnych indeksów w jednym zapytaniu.

Zrobiłem proste testy, wychodzi mi, że zawsze korzysta tylko z jednego indeksu, co jest całkiem dziwne. Pogrzebię w tym i dowiem się dlaczego.

U mnie flagę 1 ma 50% wierszy i indeks jest używany.

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Wszystko zależy od indeksów.

Jak jest indeks na kolumnie id:


"i2_b_16" btree (id) WHERE (flag & 16) = 16
"i2_b_32" btree (id) WHERE (flag & 32) = 32


to wtedy plan wygląda tak:


# explain analyze select * from flag_test2 where flag&16=16 and flag&32=32;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
Index Scan using i2_b_32 on flag_test2 (cost=0.00..2031.42 rows=250 width=8) (actual time=139.363..139.363 rows=0 loops=1)
Filter: ((flag & 16) = 16)
Rows Removed by Filter: 156521
Total runtime: 139.404 ms
(4 rows)


Natomiast gdy indeksy będą wyglądały tak:


"i_b_16" btree (flag) WHERE (flag & 16) = 16
"i_b_32" btree (flag) WHERE (flag & 32) = 32


To plan wygląda tak:


# explain analyze select * from flag_test where flag&16=16 and flag&32=32;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on flag_test (cost=1614.54..2563.16 rows=250 width=8) (actual time=1377.525..1377.525 rows=0 loops=1)
Recheck Cond: (((flag & 32) = 32) AND ((flag & 16) = 16))
Rows Removed by Index Recheck: 7442859
-> BitmapAnd (cost=1614.54..1614.54 rows=250 width=0) (actual time=335.878..335.878 rows=0 loops=1)
-> Bitmap Index Scan on i_b_32 (cost=0.00..806.42 rows=50000 width=0) (actual time=24.063..24.063 rows=156521 loops=1)
-> Bitmap Index Scan on i_b_16 (cost=0.00..807.74 rows=50000 width=0) (actual time=309.127..309.127 rows=5002763 loops=1)
Total runtime: 1377.591 ms
(7 rows)


I jeszcze rozkład danych:


# select count(*) from flag_test;
count
----------
10000000

# select count(*) from flag_test where (flag & 16) = 16;
count
---------
5002763
(1 row)

# select count(*) from flag_test where (flag & 32) = 32;
count
--------
156521

# select count(*) from flag_test where (flag & 32) = 32 and (flag & 16) = 16;
count
-------
0


Jak widać użycie jednego indeksu wcale nie musi oznaczać, że to będzie wolniejsze, niż użycie dwóch indeksów :)

PostgreSQL używa tego indeksu, który daje większą selektywność, a potem sprawdza drugi warunek.Szymon G. edytował(a) ten post dnia 10.12.12 o godzinie 13:06

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Szymon G.:
PostgreSQL używa tego indeksu, który daje większą selektywność, a potem sprawdza drugi warunek.

Tak jak myślałem.
Używanie jednego indeksu to nie specyfika PostgreSQL, w innych systemach też tak jest.
Nie-używanie indeksu widocznie włączy się dopiero przy (dużo?) powyżej 50% wybieranych rekordów. Można spróbować szukać binarnie - 75%, 87%, 92%, 96%...

Zdziwiłbym się gdyby działało zawsze, ale bazy danych ciągle się rozwijają, więc to możliwe.
Krzysztof Raczkowski

Krzysztof Raczkowski Stała współpraca,
Logifact-Systems Sp.
z o.o.

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Dla MS SQL, rozwiązanie jakie wymyśliłem jest takie...

1. Dodajemy tyle pól flaga_0, flaga_1, flaga_2, flaga_4 ... ile przewidujemy wykorzystywanych bitów...

2. Na każe pole osobny indeks.... + dołączone pola (included) które chcemy zwrócić w zapytaniu

3. Pola flaga_N można a nawet pewnie należy wyliczać w triggerze INSTEAD OF....

Wtedy zapytanie:
(...) WHERE flaga & 12 = 12

Można zamienić na:
(...) WHERE flaga_b4 = 1 AND flaga_b8 = 1

i będą wykorzystywane indeksy .. (w tym wypadku 2).... może da się prościej ? .. :)

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Krzysztof Raczkowski:
(...) WHERE flaga_b4 = 1 AND flaga_b8 = 1

i będą wykorzystywane indeksy .. (w tym wypadku 2).... może da się prościej ? .. :)

Optymista :)

Będą tak samo często wykorzystywane jak w rozwiązaniu od Szymona - gdzie indeks masz oparty o wyrażenie a nie wartość.
Krzysztof Raczkowski

Krzysztof Raczkowski Stała współpraca,
Logifact-Systems Sp.
z o.o.

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Piotr L.:
Krzysztof Raczkowski:
(...) WHERE flaga_b4 = 1 AND flaga_b8 = 1

i będą wykorzystywane indeksy .. (w tym wypadku 2).... może da się prościej ? .. :)

Optymista :)

Będą tak samo często wykorzystywane jak w rozwiązaniu od Szymona - gdzie indeks masz oparty o wyrażenie a nie wartość.

Raczej realista.... :P

1) Takiego warunku WHERE (flag & 16) = 16 w MS SQL nie założysz... jest WHERE w indeksie ale prosty.... pole [oerator] wartość... a nie funkcja_na_polu() = wartość :)

2) Sprawdzałem w planie wykonania... dla tego przypadku co podałem bierze 2 indeksy a potem robi merge wyniku.

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Krzysztof Raczkowski:
Raczej realista.... :P

1) Takiego warunku WHERE (flag & 16) = 16 w MS SQL nie założysz... jest WHERE w indeksie ale prosty.... pole [oerator] wartość... a nie funkcja_na_polu() = wartość :)

Jesteś pewny?
Coś tam do MSSQL znalazłem, ale nie testowałem:

http://technet.microsoft.com/en-us/library/cc280372.aspx
http://technet.microsoft.com/library/Cc917715
2) Sprawdzałem w planie wykonania... dla tego przypadku co podałem bierze 2 indeksy a potem robi merge wyniku.

Podaj ten plan - z uwagi na wcześniejsze (2) możesz po prostu czytać indeks (a nie wyszukiwać po nim).
Krzysztof Raczkowski

Krzysztof Raczkowski Stała współpraca,
Logifact-Systems Sp.
z o.o.

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Dwa zapytania ...


select DepartNo from std.DistStructCars where AEV & (1024+2048) = (1024+2048)
select DepartNo from std.DistStructCars where AEV_b1024 = 1 and AEV_b2048 = 1


I dwa plany ...


Obrazek

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

A indeksy do tych zapytań jakie? Po polach czy wyrażeniach?

A statystyki jakie?

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

PG ma hstore, intarray, cube.
Taki hstore pozwala na dodanie kolumny, która jest tablicą asocjacyjną. Pary klucz-wartość tej tablicy są indeksowane. Można szybko dostać listę wierszy, które mają określony zestaw par.
Przy pomocy GIN można indeksować złożone struktury -
http://www.postgresql.org/docs/current/static/gin-intr...
Krzysztof Raczkowski

Krzysztof Raczkowski Stała współpraca,
Logifact-Systems Sp.
z o.o.

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Michał Z.:
PG ma hstore, intarray, cube.
Taki hstore pozwala na dodanie kolumny, która jest tablicą asocjacyjną. Pary klucz-wartość tej tablicy są indeksowane. Można szybko dostać listę wierszy, które mają określony zestaw par.
Przy pomocy GIN można indeksować złożone struktury -
http://www.postgresql.org/docs/current/static/gin-intr...

Dzięki za podpodwiedź, tu jests idealny przykład: http://www.postgresql.org/docs/9.1/static/intarray.html

Szkoda tylko, że wiąże to rozwiązanie z daną bazą na amen.. :-)

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Krzysztof Raczkowski:
Michał Z.:
PG ma hstore, intarray, cube.
Taki hstore pozwala na dodanie kolumny, która jest tablicą asocjacyjną. Pary klucz-wartość tej tablicy są indeksowane. Można szybko dostać listę wierszy, które mają określony zestaw par.
Przy pomocy GIN można indeksować złożone struktury -
http://www.postgresql.org/docs/current/static/gin-intr...

Dzięki za podpodwiedź, tu jests idealny przykład: http://www.postgresql.org/docs/9.1/static/intarray.html
Dlatego podałem pełen zestaw "wynalazków". :)
Szkoda tylko, że wiąże to rozwiązanie z daną bazą na amen.. :-)

Jasne. Można jeszcze pójść w stronę spatial, ale... coś mi się wydaje, że to wiele nie zmieni. Chodzi mi o zdefiniowanie zestawu atrybutów jako krzywej. Kolejne atrybuty to oś X, ich wartości - Y. Obie bazy potrafią indeksować takie dane. Tyle, że - każda baza ma inny interfejs do tego.

Zasady projektowania mówią, że takie coś trzeba wydzielić - żeby nie psuło reszty systemu. Można zamknąć w stored procedures, albo na poziomie dostępu do danych - zależy co to tam ma być. Na pierwszy rzut oka fajnie to wygląda, ale pewnie jakoś te dane trzeba zmieniać... i obszar do wydzielenia się rozszerza. Jeżeli to jest zwykłe zapytanie - klient wysyła ciąg znaków i dostaje wynik. Co innego operowanie na tych danych. Standardowe rozwiązania w stylu ORM, czy kontrolki VCL w Delphi - raczej odpadają. Coś za coś - albo elastyczność, albo wydajność.
Krzysztof Raczkowski

Krzysztof Raczkowski Stała współpraca,
Logifact-Systems Sp.
z o.o.

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Michał Z.:
Jasne. Można jeszcze pójść w stronę spatial, ale... coś mi się wydaje, że to wiele nie zmieni. Chodzi mi o zdefiniowanie zestawu atrybutów jako krzywej. Kolejne atrybuty to oś X, ich wartości - Y

Kurcze powiem Ci że to b. ciekawy pomysł i tak naprawdę bardziej przenośny niż poprzednie...chyba będę musiał się tym dzisiaj pobawić. Rozumiem że krzywa, wielokąt i cos w rodzaju "flaga jest zapalona gdy jej punkt należy do figury ..."
Dominik Mikiewicz

Dominik Mikiewicz maps made easy,
www.cartomatic.pl ||
cartoninjas.net

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

spatial w tej, czy innej formie jest bardziej przenośny niż może się wydawać, ponieważ większość silników wspiera typy przestrzenne (oracle spatial, dla postgresa będzie to postgis, ms sql server wspiera geom i geography z automatu bez rozszerzeń) . i to w miarę ustandaryzowany sposób, jeżeli chodzi relacje przestrzenne i zapis danych (well... przynajmniej eskporty zgodne ze standardami OGC, tudzież reprezentacja danych jako WKT i WKB)

Sama flaga nie musi być wtedy ustawiana, ponieważ fakt zawierania się, sąsiedztwa, czy rozłączności jest istotą danych przestrzennych - i sprawdzasz takie rzeczy np wykorzystując STIntersects (składnia będzie bardzo zbliżona między silnikami, przynajmniej dla metod zgodnych z OGC)

No i indeksy będą specyficzne dla typów przestrzennych.

konto usunięte

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Krzysztof Raczkowski:
Michał Z.:
Jasne. Można jeszcze pójść w stronę spatial, ale... coś mi się wydaje, że to wiele nie zmieni. Chodzi mi o zdefiniowanie zestawu atrybutów jako krzywej. Kolejne atrybuty to oś X, ich wartości - Y

Kurcze powiem Ci że to b. ciekawy pomysł i tak naprawdę bardziej przenośny niż poprzednie...chyba będę musiał się tym dzisiaj pobawić. Rozumiem że krzywa, wielokąt i cos w rodzaju "flaga jest zapalona gdy jej punkt należy do figury ..."

Tak, coś w ten deseń. Problem jest taki, że dwa atrybuty -> dwa punty -> odcinek, a ten nie musi należeć do figury, jeżeli końce należą. Chociaż... da się to obejść, pytanie tylko czy jest sens. Zestaw 2 parametrów może oznaczać krzywą łamaną a nie 2 punkty. Ciekawe tylko, jak on sobie to na kwadraty podzieli, czy taki grzebień będzie mu się opłacało analizować. Do tego edytowanie tego... To ja już chyba zapakowałbym to w stored procedure. Dla PG wziąłbym jakiś "wynalazek", dla MS jakieś inne rozwiązanie. W T-SQL można na bitach działać. Jak operacje zapakować w stored procedure - powinno dać się jakoś z tym żyć. Chociaż... cieszę się, że to nie ja będę to supportować :)
Krzysztof Raczkowski

Krzysztof Raczkowski Stała współpraca,
Logifact-Systems Sp.
z o.o.

Temat: MS SQL (lub PostgreSQL) i wyszukiwanie po polu...

Dominik Mikiewicz:
Sama flaga nie musi być wtedy ustawiana, ponieważ fakt zawierania się, sąsiedztwa, czy rozłączności jest istotą danych przestrzennych - i sprawdzasz takie rzeczy np wykorzystując STIntersects (składnia będzie bardzo zbliżona między silnikami, przynajmniej dla metod zgodnych z OGC)

No i indeksy będą specyficzne dla typów przestrzennych.

Hmmm dzisiaj mi już chyba zwoje się przegrzewają... muszę w jakiś w miarę prosty sposób wyobrazić sobie flagi i ich hmm zbiory w przestrzeni....

A co do ustawiania stanów... hmm no coś muszę zmieniać aby raz warunek był spełniony a raz nie :)

Myślałem sobie na początku o takiej siatce 2D (powiedzmy 8x4 pola = 32 pola/flagi) Każdy prostokąt tej siatki to pewna flaga. Rekordy zawierają punkty, przykładowo jeżeli rekord zawiera 4 flagi ustawione, to powinien mieć 4 punkty zawierające się w odpowiednich 4 prostokątach...

Teraz wyszukanie wszystkich rekordów zawierających ustawioną flagę A i B.. to tak naprawdę wyszukanie tych rekordów których punkty mieszczą się w A i B.... prawda... ?

Z tego typu danymi dopiero zaczynam .. więc nie wiem czy mój tok rozumowania jest prawidłowy...

No i kolejne pytanie... szybkie toto jest ? :D

Następna dyskusja:

przeniesienie danych z Oral...




Wyślij zaproszenie do