RããªãŒãšæ¯èŒãã
Z次æ²ç·ã«åºã¥ãã€ã³ããã¯ã¹ã«ã¯ãå€ãã®å©ç¹ããããŸãã
- éåžžã®BããªãŒãšããŠå®è£
ãããŠããŸããã
- ããã«ãBããªãŒããŒãžã¯ããåªããå
¥åå¯èœæ§ãåããŠããã
- ZããŒèªäœã¯ããã³ã³ãã¯ãã§ã
- RããªãŒãšã¯ç°ãªããBããªãŒã«ã¯èªç¶ãªãã©ããŒã¹é åºããããŸã
- BããªãŒã®æ§ç¯ãé«éå
- BããªãŒã®ãã©ã³ã¹ããšããŠãã
- BããªãŒã¯ãããŒãžåå²/ãã¥ãŒãªã¹ãã£ãã¯ã®ããŒãžã«äŸåãããããç解ãããã
- BããªãŒã¯çµ¶ããå€åããŠãå£åããŸãã
- ...
ãã ããZãªãŒããŒã«åºã¥ãã€ã³ããã¯ã¹ã«ã¯æ¬ ç¹ããããŸã-æ¯èŒçäœãããã©ãŒãã³ã¹ã§ã:)ã ã«ããã®äžã§ããã®æ¬ ç¹ãäœã«é¢ä¿ããŠãããããããŠããã䜿ã£ãŠäœããè¡ãããšãã§ãããã©ãããç解ããããšããŸãã
ãããããZæ²ç·ã®æå³ã¯æ¬¡ã®ãšããã§ããçµæãšããŠãx座æšãšy座æšã®ãããã1ã€ã®å€ã§äº€äºã«å
¥ãæ¿ããŸãã äŸã¯ïŒx = 33ïŒ
010 0001 ïŒãy = 22ïŒ
01 0110 ïŒãZ = 1577ïŒ
0 1 1 0 0 0 1 0 1 0 0 1 ïŒã2ã€ã®ãã€ã³ãã®åº§æšãè¿ãå ŽåãZ-ãããã®å€ã¯è¿ããªããŸãã
3次å
ïŒãŸãã¯ãã以äžïŒããŒãžã§ã³ãåæ§ã«é
眮ããã3ïŒãŸãã¯ãã以äžïŒã®åº§æšã®æ°åã亀äºã«äžŠã¹ãŸãã
ãŸããç¹å®ã®ç¯å²ã§æ€çŽ¢ããã«ã¯ããã®ç¯å²ã®Zæ²ç·ã®ãã¹ãŠã®å€ããã©ã¹ã¿ã©ã€ãºãããé£ç¶ããééãèŠã€ããŠããããããæ€çŽ¢ããå¿
èŠããããŸãã
ãšã¯ã¹ãã³ã[111000 ... 111000] [111400 ... 111400]ïŒ675ééïŒãå³äžé
ïŒåé£ç¶ããªã©ã€ã³ã¯1ééïŒã®å³ã§ãã
ãŸããããšãã°ãç¯å²[111000 ... 111000] [112000 ... 112000]ã®å Žåã1688ã®é£ç¶ããééãåŸãããŸããæããã«ããã®æ°ã¯äž»ã«å¢çã®é·ãã«äŸåããŸãã å°æ¥ãèŠããšããã¹ãããŒã¿ã§ã¯ã6ééã§15ãã€ã³ãããã®ç¯å²ã«å
¥ããŸããã
ã¯ãããããã®ééã®ã»ãšãã©ã¯ã1ã€ã®å€ããçž®éãããŸã§å°ãããªããŸãã ããã«ããããããããã®ãã¹ãŠã®ç¯å²ã«å€ã1ã€ãããªãå Žåã§ãããã®å€ã¯ä»»æã®ééã«ãããŸãã ãããŠãããã奜ããã©ããã«ãããããã1688åãã¹ãŠã®ãµãã¯ãšãªãå®è¡ããŠãå®éã«ãã€ã³ããããã€ãããã調ã¹ãå¿
èŠããããŸãã
å·Šäžã®å€ããå³äžã®ãã¹ãŠã衚瀺ããããšã¯ãªãã·ã§ã³ã§ã¯ãããŸããããã®å Žåã®è§åºŠã®éãã¯3 144 768ã§ãã3å以äžã®ããŒã¿ãèŠãå¿
èŠããããããã¯ææªã®å Žåãšã¯ã»ã©é ãã§ãã ããšãã°ããšã¯ã¹ãã³ã[499500 ... 499500] [500500 ... 500500]ã¯ã135,263,808ã®å€ã®ç¯å²ïŒãšã¯ã¹ãã³ãé åã®135åïŒãæäŸããŸãã
ãããŠãããã§äŒçµ±çãªè³ªåãããããšãã§ããŸã-
ããã...
äžè¬ã«ç©ºã®ã€ã³ããã¯ã¹ããããšä»®å®ãããšããããç解ããããã«ãããã®æ°çŸããã³æ°åã®ãµãã¯ãšãªããã¹ãŠå®è¡ããå¿
èŠããããŸããïŒ ãããã1ã€ã§ååã§ã-å·Šäžããå³äžãžã
ããã§ãç¯å²ãååã«å°ãããããŒã¿ããŸã°ãã§ãäœããèŠã€ããå¯èœæ§ãå°ãããšããŸãã é
ããé
ãŸã§åããªã¯ãšã¹ããå®è¡ããŠã¿ãŸãããã äœãèŠã€ãããªãã£ãå ŽåãäœããããŸããã ããã§ãªããã°ããã£ã³ã¹ããããŸãã ããããèŠãããã«ãé
ããé
ãžã®ãªã¯ãšã¹ãã«ãã£ãŠã¹ã€ãŒããããé åã¯ãæ€çŽ¢ç¯å²ãããäœåã倧ãããªãå¯èœæ§ããããæããã«äžèŠãªããŒã¿ãèªã¿åãå¿
èŠã¯ãããŸããã ãããã£ãŠãã«ãŒãœã«å
šäœã衚瀺ããã®ã§ã¯ãªããããããæå°ã®Zå€ã®ã¿ãååŸããŸãã ãããè¡ãã«ã¯ãã¯ãšãªã¯ïŒorder byïŒããã³ïŒtop 1ïŒã䜿çšããŠå®è¡ãããŸãã
ã§ããããäœããã®æå³ããããŸãã ãã®å€ãç§ãã¡ã®ç¯å²ããã§ã¯ãªããšä»®å®ãããšãããã¯äœãäžããããšãã§ããŸããïŒ [1 ... N]ã®ãµãã¯ãšãªç¯å²ã®ãœãŒããããé
åãããããšãæãåºããŠãã ããã ãã€ããªæ€çŽ¢ãå®è¡ããmãšm + 1ã®éã§ãã£ãŠãããã®å€ãçµã蟌ãŸãããµãã¯ãšãªãèŠã€ããŸãã é©ãã¹ãããšã«ãããã¯1ããmãŸã§ã®ãªã¯ãšã¹ããçç¥ããããšãã§ããããšãæå³ããæããã«ããã«ã¯äœããªãã
å€ãç§ãã¡ã®ç¯å²ã«å±ããŠããå Žåãããã¯ç§ãã¡ã®ç¯å²ã®1ã€ã«å
¥ããmã§ã¯ãããŸãããã©ãã§ããããèŠã€ããããšãã§ããŸãã åãšåæ§ã«ãçªå·1 ... m-1ã®ãªã¯ãšã¹ãã¯çç¥ã§ããŸãã ããããçªå·mã®ééã¯ããã®äžã«ãããã¹ãŠã®ãã®ãç§ãã¡ã«äžããå¥åã®èŠæ±ã«å€ããŸãã
ãŸãããŸã ããŒã¿ãæ®ã£ãŠãããããããªãã®ã§ãç¶ããŸãããã å床ããªã¯ãšã¹ããå®è¡ããŸãããã³ãŒããŒããã³ãŒããŒã§ã¯ãªããéém + 1ã®éå§ããå³äžã³ãŒããŒãŸã§ã§ãã ãããŠãééã®ãªã¹ãã®æåŸã«éãããŸã§ãããè¡ããŸãã
ãããå
šäœã®èãæ¹ã§ãã倧éã®ããŒã¿ã倧éã®ããŒã¿ãç¯å²å
ã«å
¥ã£ãå Žåã§ãæ£åžžã«æ©èœããããšã«æ³šæããŠãã ããã äžèŠãããšãããã¯ãªã¯ãšã¹ãã®æ°ãæ ¹æ¬çã«æžãããäœæ¥ãé«éåããŸãã
ã¢ã€ãã¢ãå®éã«ãã¹ããããšããæ¥ãŸããã ãã¹ããµã€ããšããŠã
PostgeSQL 9.6.1ã
GiSTã䜿çšããŸãã 枬å®ã¯2ã€ã®ã³ã¢ãš4 GBã®RAMãåããæ§ãããªä»®æ³ãã·ã³ã§å®è¡ããããããæéã«ã¯çµ¶å¯Ÿå€ã¯ãããŸããããèªã¿åãããããŒãžæ°ã¯ä¿¡é Œã§ããŸãã
ãœãŒã¹ããŒã¿
ãšã¯ã¹ãã³ã[0 ... 1 000 000] [0 ... 1 000 000]ã®1ååã®ã©ã³ãã ãã€ã³ããããŒã¿ãšããŠäœ¿çšãããŸããã
2次å
ã®ãã€ã³ãããŒã¿ã®ããŒãã«ãååŸããŠã¿ãŸãããã
create table test_points (x integer,y integer);
ããŒã¿ãäœæããŸãã
gawkã¹ã¯ãªããBEGIN {
forïŒi = 0; i <100000000; i ++ïŒ
{
x = intïŒ1000000 * randïŒïŒïŒ;
y = intïŒ1000000 * randïŒïŒïŒ;
print x "\ t" z;
}
exitïŒ0ïŒ;
}
çµæã®ãã¡ã€ã«ã䞊ã¹æ¿ãïŒä»¥äžã®èª¬æïŒãCOPYæŒç®åã䜿çšããŠããŒãã«ã«å
¥åããŸãã
COPY test_points from '/home/.../data.csv';
ããŒãã«ãžã®å
¥åã«ã¯æ°åããããŸãã ããŒã¿ãµã€ãºïŒ\ dt +ïŒ-4358 Mb
RããªãŒ
察å¿ããã€ã³ããã¯ã¹ã¯æ¬¡ã®ã³ãã³ãã§äœæãããŸãïŒ
create index test_gist_idx on test_points using gist ((point(x,y)));
ãããããã¥ã¢ã³ã¹ããããŸãã ã€ã³ããã¯ã¹ã¯éåžžã«é·ãéã©ã³ãã ããŒã¿ã«åºã¥ããŠäœæãããŸãïŒãããã®å Žåããäœæè
ã«ã¯äžæ©ã§äœæããæéããããŸããã§ããïŒã äºåã«äžŠã¹æ¿ããããããŒã¿ã®æ§ç¯ã«ã¯ãçŽ1æéããããŸããã
ã€ã³ããã¯ã¹ãµã€ãºïŒ\ di +ïŒ-9031 Mb
åºæ¬çã«ãããŒãã«å
ã®ããŒã¿ã®é åºã¯éèŠã§ã¯ãããŸããããããŸããŸãªæ¹æ³ã«å
±éããå¿
èŠãããããããœãŒããããããŒãã«ã䜿çšããå¿
èŠããããŸããã
ãã¹ããªã¯ãšã¹ãã¯æ¬¡ã®ããã«ãªããŸãã
select count(1) from test_points where point(x,y) <@ box(point("xmin","ymin"),point("xmax","ymax"));
éåžžã®ã€ã³ããã¯ã¹ã®æ€èšŒ
ããã©ãŒãã³ã¹ããã¹ãããããã«ãxãšyã«ãã£ãŠåå¥ã®ã€ã³ããã¯ã¹ã§ç©ºéã¯ãšãªãå®è¡ããŸãã 次ã®ããã«äœæãããŸãã
create index x_test_points on test_points (x); create index y_test_points on test_points (y);
æ°åããããŸãã
ãã¹ããªã¯ãšã¹ãïŒ
select count(1) from test_points where x >= "xmin" and x <= "xmax" and y >= "ymin" and y <= "ymax";
Z-index
ããã§ãxãy座æšãZå€ã«å€æã§ããé¢æ°ãå¿
èŠã§ãã
æåã«ã
æ¡åŒµåãäœæãããã®äžã«é¢æ°ãäœæããŸãã
CREATE FUNCTION zcurve_val_from_xy(bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
圌女ã®äœïŒ static uint32 stoBits[8] = {0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080}; uint64 zcurve_fromXY (uint32 ix, uint32 iy) { uint64 val = 0; int curmask = 0xf; unsigned char *ptr = (unsigned char *)&val; int i; for (i = 0; i < 8; i++) { int xp = (ix & curmask) >> (i<<2); int yp = (iy & curmask) >> (i<<2); int tmp = (xp & stoBits[0]) | ((yp & stoBits[0])<<1) | ((xp & stoBits[1])<<1) | ((yp & stoBits[1])<<2) | ((xp & stoBits[2])<<2) | ((yp & stoBits[2])<<3) | ((xp & stoBits[3])<<3) | ((yp & stoBits[3])<<4); curmask <<= 4; ptr[i] = (unsigned char)tmp; } return val; } Datum zcurve_val_from_xy(PG_FUNCTION_ARGS) { uint64 v1 = PG_GETARG_INT64(0); uint64 v2 = PG_GETARG_INT64(1); PG_RETURN_INT64(zcurve_fromXY(v1, v2)); }
ããã§ïŒãã¡ããCREATE EXTENSIONã®åŸïŒãZ-indexã¯æ¬¡ã®ããã«æ§ç¯ãããŸãïŒ
create index zcurve_test_points on test_points(zcurve_val_from_xy(x, y));
ããã«ã¯æ°åããããŸãïŒããŒã¿ã®äžŠã¹æ¿ãã¯äžèŠã§ãïŒã
ã€ã³ããã¯ã¹ãµã€ãºïŒ\ di +ïŒ-2142 MbïŒRããªãŒããã4åå°ããïŒ
Z-Indexæ€çŽ¢
ãããã£ãŠãæåã®ïŒãåçŽããšåŒã¶ïŒããŒãžã§ã³ã§ã¯ã次ã®ããã«ããŸãã
- ãµã€ãºdx * dyã®ãšã¯ã¹ãã³ãã®å Žåã察å¿ãããµã€ãºã®èå¥åã®é
åãéå§ããŸã
- ç¯å²å
ã®åãã€ã³ãã«ã€ããŠãZå€ãèšç®ãããŸã
- èå¥åã®é
åã䞊ã¹æ¿ãã
- é£ç¶ééãèŠã€ãã
- ééããšã«ã次ã®åœ¢åŒã®ãµãã¯ãšãªãå®è¡ããŸãã
select * from test_points where zcurve_val_from_xy(x, y) between $1 and $2
- çµæãåŸã
ãã®ãªãã·ã§ã³ã䜿çšããŠæ€çŽ¢ããã«ã¯ãé¢æ°ïŒäžã®æ¬æïŒã䜿çšããŸãã
CREATE FUNCTION zcurve_oids_by_extent(bigint, bigint, bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
ãã®é¢æ°ã䜿çšãã空éã¯ãšãªã¯æ¬¡ã®ããã«ãªããŸãã
select zcurve_oids_by_extent("xmin","ymin","xmax","ymax") as count;
ãã®é¢æ°ã¯ãããæ°ã®ã¿ãè¿ããŸããããŒã¿èªäœã¯ãå¿
èŠã«å¿ããŠã
elogïŒINFO ...ïŒ ãã䜿çšããŠè¡šç€ºã§ããŸãã
2çªç®ã®æ¹åãããïŒããµã³ãã«ããšåŒã³ãŸãããïŒãªãã·ã§ã³ã¯æ¬¡ã®ãšããã§ãã
- ãµã€ãºdx * dyã®ãšã¯ã¹ãã³ãã«å¯ŸããŠã察å¿ãããµã€ãºã®èå¥åã®é
åãéå§ããŸã
- ç¯å²å
ã®åãã€ã³ãã«ã€ããŠãZå€ãèšç®ãããŸã
- èå¥åã®é
åããœãŒãããŸã
- é£ç¶ééãèŠã€ãã
- èŠã€ãã£ãæåã®ééããéå§ããŸãã
- 次ã®ã¿ã€ãã®ããã¹ãããªã¯ãšã¹ããå®è¡ããŸãïŒãã©ã¡ãŒã¿ãŒ-ééã®å¢çïŒïŒ
select * from test_points where zcurve_val_from_xy(x, y) between $1 and $2 order by zcurve_val_from_xy(x, y) limit 1
- ãã®ã¯ãšãªã¯ãçŸåšã®ãã¹ãééã®éå§ããæ€çŽ¢ç¯å²ã®çµäºãŸã§ã®Zå€ãæå°ã®ããŒãã«ã®è¡ãæäŸããŸãã
- èŠæ±ã§äœãèŠã€ãããªãã£ãå Žåãæ€çŽ¢ç¯å²ã«ããŒã¿ãæ®ã£ãŠããªããããçµäºããŸãã
- ããã§ãèŠã€ãã£ãZå€ãåæã§ããŸãã
- ããããã®ééã«åãŸããã©ããã確èªããŸãã
- ããã§ãªãå Žåã¯ã次ã®æ®ãã®ééã®çªå·ãèŠã€ããŠãã¹ããã5ã«é²ã¿ãŸãã
- ã²ã©ãå Žåã¯ããã®ã¿ã€ãã®ééã§ã¯ãšãªãå®è¡ããŸãã
select * from test_points where zcurve_val_from_xy(x, y) between $1 and $2
- 次ã®ééãåããã¹ããã5ã«é²ã¿ãŸãã
ãã®ãªãã·ã§ã³ã䜿çšããŠæ€çŽ¢ããã«ã¯ã次ã®é¢æ°ã䜿çšããŸãã
CREATE FUNCTION zcurve_oids_by_extent_ii(bigint, bigint, bigint, bigint) RETURNS bigint AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
ãã®é¢æ°ã䜿çšãã空éã¯ãšãªã¯æ¬¡ã®ããã«ãªããŸãã
select zcurve_oids_by_extent_ii("xmin","ymin","xmax","ymax") as count;
ãŸãããã®é¢æ°ã¯ãããæ°ã®ã¿ãè¿ããŸãã
ã©ã¹ã¿ã©ã€ãº
説æãããŠããã¢ã«ãŽãªãºã ã§ã¯ãééã®ãªã¹ããååŸããããã«ãéåžžã«åçŽã§éå¹ççãªãã©ã¹ã¿ã©ã€ãºãã¢ã«ãŽãªãºã ã䜿çšãããŠããŸãã
äžæ¹ã圌ã®äœåã®å¹³åæéãé©åãªãµã€ãºã®ã©ã³ãã ãªç¯å²ã§æž¬å®ããããšã¯é£ãããããŸããã ããã«ãããŸãïŒ
ãšã¯ã¹ãã³ãdx * dy | SERPã®äºæ³ãããå¹³åãã€ã³ãæ° | æéãããªç§ |
---|
100X100 | 1 | .96ïŒ.37 + .59ïŒ |
316X316 | 10 | 11ïŒ3.9 + 7.1ïŒ |
1000X1000 | 100 | 119.7ïŒ35 + 84.7ïŒ |
3162X3162 | 1000 | 1298ïŒ388 + 910ïŒ |
10000X10000 | 10,000 | 14696ïŒ3883 + 10813ïŒ |
ã«ãã³å
ã«2ã€ã®ãã§ãŒãºãåå¥ã«ç€ºãããŠããŸã-Zå€ã®èšç®ãšãœãŒã
çµæ
ããŒã¿ãå«ãããããããŒãã«ã次ã«ç€ºããŸãã
Nãã€ã³ã | çš®é¡ | æéïŒããªç§ïŒ | èªã¿ãŸã | å
±æããã |
---|
1 | XïŒY rtree Zå€ Zå€II | 43.6 .5 8.3ïŒ9.4ïŒ 1.1ïŒ2.2ïŒ | 59.0173 4.2314 4.0988 4.1984ïŒ12.623ïŒ | 6.1596 2.6565 803.171 20.1893ïŒ57.775ïŒ |
10 | XïŒY rtree Zå€ Zå€II | 83.5 .6 15ïŒ26ïŒ 4ïŒ15ïŒ | 182.592 13.7341 14.834 14.832ïŒ31.439ïŒ | 9.24363 2.72466 2527.56 61.814ïŒ186.314ïŒ |
100 | XïŒY rtree Zå€ Zå€II | 220 2.1 80ïŒ200ïŒ 10ïŒ130ïŒ | 704.208 95.8179 95.215 96.198ïŒ160.443ïŒ | 16.528 5.3754 8007.3 208.214ïŒ600.049ïŒ |
1000 | XïŒY rtree Zå€ Zå€II | 740 12 500ïŒ1800ïŒ 200ïŒ1500ïŒ | 3176.06 746.617 739.32 739.58ïŒ912.631ïŒ | 55.135 25.439 25816 842.88ïŒ2028.81ïŒ |
10,000 | XïŒY rtree Zå€ Zå€II | 2,500 70 ... 1 200 4700ïŒ19000ïŒ 1300ïŒ16000ïŒ | 12393.2 4385.64 4284.45 4305.78ïŒ4669ïŒ | 101.43 121.56 86274.9 5785.06ïŒ9188ïŒ |
Npoints -SERPã®å¹³åãã€ã³ãæ°ã
ã¿ã€ã -
- 'XïŒY'-xããã³yã«ããåã
ã®ã€ã³ããã¯ã¹ã®äœ¿çš
- 'rtree'-RããªãŒãä»ããèŠæ±
- Zå€-ééã眮ããå
¬æ£ãªæ€çŽ¢
- 'Z-value-ii'-ãµã³ãã«ã䜿çšããŠééã§æ€çŽ¢
æéïŒããªç§ïŒ -ãªã¯ãšã¹ãå®è¡ã®å¹³åæéã ãããã®æ¡ä»¶äžã§ã¯ãå€ã¯éåžžã«äžå®å®ã§ãDBMSãã£ãã·ã¥ãä»®æ³ãã·ã³ã®ãã£ã¹ã¯ãã£ãã·ã¥ãããã³ãã¹ãã·ã¹ãã ã®ãã£ã¹ã¯ãã£ãã·ã¥ã«äŸåããŸãã ããã§åç
§ããå¯èœæ§ãé«ããªããŸãã
Z-valueããã³Z-value-iiã«ã¯ã2ã€ã®æ°å€ãäžããããŸãã æ¬åŒ§å
ã¯å®éã®æéã§ãã æ¬åŒ§ãªã-æéãããã©ã¹ã¿ã©ã€ãºãã®ã³ã¹ããåŒãããã®ãèªã¿åã -èŠæ±ããšã®èªã¿åãã®å¹³åæ°ïŒEXPLAINïŒANALYZEãBUFFERSïŒãä»ããŠåä¿¡ïŒ
å
±æããã -ãããã¡ã®åŒã³åºãåæ°ïŒ...ïŒ
Z-value-iiã®å Žåãèªã¿åããšå
±æã®ãããåã«2ã€ã®æ°å€ã衚瀺ãããŸãã æ¬åŒ§å
ã¯æž¬å®å€ã®ç·æ°ã§ãã æ¬åŒ§ãªã-order byããã³limit 1ã䜿çšããã¯ãšãªã®èª¿æ»ãé€ã ãããã£ãŠããã®ãããªèŠæ±ã«é¢ããçµ±èšã¯äžèŠãšèŠãªãããŸããããåç
§çšã«æäŸãããŸãããããããµãŒããŒãšä»®æ³ãã·ã³ã§ã®2åç®ã®å®è¡ã§æéã衚瀺ãããŸãã èªã¿åããããããã¡ãŒã®æ°ã¯ãæ°ããçæããããµãŒããŒäžã«ãããŸãã
ãã¹ãŠã®ã¿ã€ãã®ã¯ãšãªã§ãããŒãã«èªäœã®ããŒã¿ã¯ã€ã³ããã¯ã¹ã«å±ããŠããŸããã§ããã ãã ããããã¯åãããŒãã«ããã®åãããŒã¿ã§ããããããã¹ãŠã®çš®é¡ã®ã¯ãšãªã§å®æ°å€ãååŸããŸããã
çµè«
- RããªãŒã¯éçãªç¶æ
ã§ã¯äŸç¶ãšããŠéåžžã«åªããŠãããããŒãžèªã¿åãã®å¹çã¯éåžžã«é«ããªã£ãŠããŸãã
- ãã ããZãªãŒããŒã€ã³ããã¯ã¹ã¯ãå¿
èŠãªããŒã¿ããªãããŒãžãèªã¿åãå¿
èŠãããå ŽåããããŸãã ããã¯ããã¹ãã«ãŒãœã«ãééã®éã«ããå Žåã«çºçãããã®ééã«ã¯å€ãã®å€éšãã€ã³ããååšããå¯èœæ§ããããç¹å®ã®ããŒãžã«ã¯éèšããŒã¿ãå«ãŸããŸããã
- ããã«ãããããããããé«å¯åºŠã®ããã±ãŒãžã³ã°ã«ãããZãªãŒããŒã¯å®éã«èªã¿åãããããŒãžæ°ã«ãããŠRããªãŒã«è¿ããªããŸã ã ããã¯ã æœåšçã« ZãªãŒããŒãåæ§ã®ããã©ãŒãã³ã¹ãçæã§ããããšã瀺åããŠããŸãã
- ZãªãŒããŒã€ã³ããã¯ã¹ã¯ããã£ãã·ã¥ããèšå€§ãªæ°ã®ããŒãžãèªã¿åããŸãã èŠæ±ã¯åãå Žæã§äœåºŠãè¡ãããŸãã äžæ¹ããããã®æž¬å®å€ã¯æ¯èŒçå®äŸ¡ã§ãã
- 倧èŠæš¡ãªã¯ãšãªã§ã¯ãZãªãŒããŒã®é床ãRããªãŒããã倧å¹
ã«äœäžããŸãã ããã¯ããµãã¯ãšãªãå®è¡ããããã«é«ã¬ãã«ã§é«éã§ã¯ãªãæ©æ§ã§ããSPIã䜿çšãããšããäºå®ã«ãã£ãŠèª¬æãããŸãã ãããŠããã¡ãããã©ã¹ã¿ã©ã€ãºãã§ã¯ãäœããããå¿
èŠããããŸãã
- äžèŠãééãµã³ãã«ã䜿çšããŠãäœæ¥ã倧å¹
ã«å éãããããšã¯ãããŸããã§ããããæ£åŒã«ã¯ããŒãžèªã¿åãã®çµ±èšãããã«æªåããŸããã ãã ããããã¯äœ¿çšããå¿
èŠããã£ãé«ã¬ãã«ã®è³éã®ã³ã¹ãã§ããããšãç解ããå¿
èŠããããŸãã æœåšçã«ãZãªãŒããŒããŒã¹ã®ã€ã³ããã¯ã¹ã¯ãããã©ãŒãã³ã¹ã®ç¹ã§ã¯RããªãŒããæªããªããä»ã®æŠè¡çããã³æè¡çç¹æ§ã®ç¹ã§ã¯ã¯ããã«åªããŠããŸãã
èŠèŸŒã¿
åçã®æ¡ä»¶ã§RããªãŒãšç«¶åã§ããZãªãŒããŒã«åºã¥ããæ¬æ Œçãªç©ºéã€ã³ããã¯ã¹ãäœæããã«ã¯ã次ã®åé¡ã解決ããå¿
èŠããããŸãã
- ç¯å²ããšã®ãµãã€ã³ã¿ãŒãã«ã®ãªã¹ããååŸããããã®å®äŸ¡ãªã¢ã«ãŽãªãºã ãèãåºã
- ã€ã³ããã¯ã¹ããªãŒãžã®äœã¬ãã«ã¢ã¯ã»ã¹ã«åãæ¿ãã
幞ããªããšã«ããããã®äž¡æ¹ã¯äžå¯èœãšã¯æããŸããã
ãœãŒã¹ã³ãŒã #include "postgres.h" #include "catalog/pg_type.h" #include "fmgr.h" #include <string.h> #include "executor/spi.h" PG_MODULE_MAGIC; uint64 zcurve_fromXY (uint32 ix, uint32 iy); void zcurve_toXY (uint64 al, uint32 *px, uint32 *py); static uint32 stoBits[8] = {0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080}; uint64 zcurve_fromXY (uint32 ix, uint32 iy) { uint64 val = 0; int curmask = 0xf; unsigned char *ptr = (unsigned char *)&val; int i; for (i = 0; i < 8; i++) { int xp = (ix & curmask) >> (i<<2); int yp = (iy & curmask) >> (i<<2); int tmp = (xp & stoBits[0]) | ((yp & stoBits[0])<<1) | ((xp & stoBits[1])<<1) | ((yp & stoBits[1])<<2) | ((xp & stoBits[2])<<2) | ((yp & stoBits[2])<<3) | ((xp & stoBits[3])<<3) | ((yp & stoBits[3])<<4); curmask <<= 4; ptr[i] = (unsigned char)tmp; } return val; } void zcurve_toXY (uint64 al, uint32 *px, uint32 *py) { unsigned char *ptr = (unsigned char *)&al; int ix = 0; int iy = 0; int i; if (!px || !py) return; for (i = 0; i < 8; i++) { int tmp = ptr[i]; int tmpx = (tmp & stoBits[0]) + ((tmp & stoBits[2])>>1) + ((tmp & stoBits[4])>>2) + ((tmp & stoBits[6])>>3); int tmpy = ((tmp & stoBits[1])>>1) + ((tmp & stoBits[3])>>2) + ((tmp & stoBits[5])>>3) + ((tmp & stoBits[7])>>4); ix |= tmpx << (i << 2); iy |= tmpy << (i << 2); } *px = ix; *py = iy; } PG_FUNCTION_INFO_V1(zcurve_val_from_xy); Datum zcurve_val_from_xy(PG_FUNCTION_ARGS) { uint64 v1 = PG_GETARG_INT64(0); uint64 v2 = PG_GETARG_INT64(1); PG_RETURN_INT64(zcurve_fromXY(v1, v2)); } static const int s_maxx = 1000000; static const int s_maxy = 1000000; #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif static int compare_uint64( const void *arg1, const void *arg2 ) { const uint64 *a = (const uint64 *)arg1; const uint64 *b = (const uint64 *)arg2; if (*a == *b) return 0; return *a > *b ? 1: -1; } SPIPlanPtr prep_interval_request(); int fin_interval_request(SPIPlanPtr pplan); int run_interval_request(SPIPlanPtr pplan, uint64 v0, uint64 v1); SPIPlanPtr prep_interval_request() { SPIPlanPtr pplan; char sql[8192]; int nkeys = 2; Oid argtypes[2] = {INT8OID, INT8OID}; /* key types to prepare execution plan */ int ret =0; if ((ret = SPI_connect()) < 0) /* internal error */ elog(ERROR, "check_primary_key: SPI_connect returned %d", ret); snprintf(sql, sizeof(sql), "select * from test_points where zcurve_val_from_xy(x, y) between $1 and $2"); /* Prepare plan for query */ pplan = SPI_prepare(sql, nkeys, argtypes); if (pplan == NULL) /* internal error */ elog(ERROR, "check_primary_key: SPI_prepare returned %d", SPI_result); return pplan; } int fin_interval_request(SPIPlanPtr pplan) { SPI_finish(); return 0; } int run_interval_request(SPIPlanPtr pplan, uint64 v0, uint64 v1) { Datum values[2]; /* key types to prepare execution plan */ Portal portal; int cnt = 0, i; values[0] = Int64GetDatum(v0); values[1] = Int64GetDatum(v1); portal = SPI_cursor_open(NULL, pplan, values, NULL, true); if (NULL == portal) /* internal error */ elog(ERROR, "check_primary_key: SPI_cursor_open"); for (;;) { SPI_cursor_fetch(portal, true, 8); if (0 == SPI_processed || NULL == SPI_tuptable) break; { TupleDesc tupdesc = SPI_tuptable->tupdesc; for (i = 0; i < SPI_processed; i++) { HeapTuple tuple = SPI_tuptable->vals[i]; //elog(INFO, "%s, %s", SPI_getvalue(tuple, tupdesc, 1), SPI_getvalue(tuple, tupdesc, 2)); cnt++; } } } SPI_cursor_close(portal); return cnt; } PG_FUNCTION_INFO_V1(zcurve_oids_by_extent); Datum zcurve_oids_by_extent(PG_FUNCTION_ARGS) { SPIPlanPtr pplan; uint64 x0 = PG_GETARG_INT64(0); uint64 y0 = PG_GETARG_INT64(1); uint64 x1 = PG_GETARG_INT64(2); uint64 y1 = PG_GETARG_INT64(3); uint64 *ids = NULL; int cnt = 0; int sz = 0, ix, iy; x0 = MIN(x0, s_maxx); y0 = MIN(y0, s_maxy); x1 = MIN(x1, s_maxx); y1 = MIN(y1, s_maxy); if (x0 > x1) elog(ERROR, "xmin > xmax"); if (y0 > y1) elog(ERROR, "ymin > ymax"); sz = (x1 - x0 + 1) * (y1 - y0 + 1); ids = (uint64*)palloc(sz * sizeof(uint64)); if (NULL == ids) /* internal error */ elog(ERROR, "cant alloc %d bytes in zcurve_oids_by_extent", sz); for (ix = x0; ix <= x1; ix++) for (iy = y0; iy <= y1; iy++) { ids[cnt++] = zcurve_fromXY(ix, iy); } qsort (ids, sz, sizeof(*ids), compare_uint64); cnt = 0; pplan = prep_interval_request(); { // FILE *fl = fopen("/tmp/ttt.sql", "w"); int cur_start = 0; int ix; for (ix = cur_start + 1; ix < sz; ix++) { if (ids[ix] != ids[ix - 1] + 1) { cnt += run_interval_request(pplan, ids[cur_start], ids[ix - 1]); // fprintf(fl, "EXPLAIN (ANALYZE,BUFFERS) select * from test_points where zcurve_val_from_xy(x, y) between %ld and %ld;\n", ids[cur_start], ids[ix - 1]); // elog(INFO, "%d -> %d (%ld -> %ld)", cur_start, ix - 1, ids[cur_start], ids[ix - 1]); // cnt++; cur_start = ix; } } if (cur_start != ix) { cnt += run_interval_request(pplan, ids[cur_start], ids[ix - 1]); // fprintf(fl, "EXPLAIN (ANALYZE,BUFFERS) select * from test_points where zcurve_val_from_xy(x, y) between %ld and %ld;\n", ids[cur_start], ids[ix - 1]); // elog(INFO, "%d -> %d (%ld -> %ld)", cur_start, ix - 1, ids[cur_start], ids[ix - 1]); } // fclose(fl); } fin_interval_request(pplan); pfree(ids); PG_RETURN_INT64(cnt); } //------------------------------------------------------------------------------------------------ struct interval_ctx_s { SPIPlanPtr cr_; SPIPlanPtr probe_cr_; uint64 cur_val_; uint64 top_val_; FILE * fl_; }; typedef struct interval_ctx_s interval_ctx_t; int prep_interval_request_ii(interval_ctx_t *ctx); int run_interval_request_ii(interval_ctx_t *ctx, uint64 v0, uint64 v1); int probe_interval_request_ii(interval_ctx_t *ctx, uint64 v0); int fin_interval_request_ii(interval_ctx_t *ctx); int prep_interval_request_ii(interval_ctx_t *ctx) { char sql[8192]; int nkeys = 2; Oid argtypes[2] = {INT8OID, INT8OID}; /* key types to prepare execution plan */ int ret =0; if ((ret = SPI_connect()) < 0) /* internal error */ elog(ERROR, "check_primary_key: SPI_connect returned %d", ret); snprintf(sql, sizeof(sql), "select * from test_points where zcurve_val_from_xy(x, y) between $1 and $2"); ctx->cr_ = SPI_prepare(sql, nkeys, argtypes); if (ctx->cr_ == NULL) /* internal error */ elog(ERROR, "check_primary_key: SPI_prepare returned %d", SPI_result); snprintf(sql, sizeof(sql), "select * from test_points where zcurve_val_from_xy(x, y) between $1 and %ld order by zcurve_val_from_xy(x::int4, y::int4) limit 1", ctx->top_val_); ctx->probe_cr_ = SPI_prepare(sql, 1, argtypes); if (ctx->probe_cr_ == NULL) /* internal error */ elog(ERROR, "check_primary_key: SPI_prepare returned %d", SPI_result); return 1; } int probe_interval_request_ii(interval_ctx_t *ctx, uint64 v0) { Datum values[1]; /* key types to prepare execution plan */ Portal portal; values[0] = Int64GetDatum(v0); { // uint32 lx, ly; // zcurve_toXY (v0, &lx, &ly); // // elog(INFO, "probe(%ld:%d,%d)", v0, lx, ly); } if (ctx->fl_) fprintf(ctx->fl_, "EXPLAIN (ANALYZE,BUFFERS) select * from test_points where zcurve_val_from_xy(x, y) between %ld and %ld order by zcurve_val_from_xy(x::int4, y::int4) limit 1;\n", v0, ctx->top_val_); portal = SPI_cursor_open(NULL, ctx->probe_cr_, values, NULL, true); if (NULL == portal) /* internal error */ elog(ERROR, "check_primary_key: SPI_cursor_open"); { SPI_cursor_fetch(portal, true, 1); if (0 != SPI_processed && NULL != SPI_tuptable) { TupleDesc tupdesc = SPI_tuptable->tupdesc; bool isnull; HeapTuple tuple = SPI_tuptable->vals[0]; Datum dx, dy; uint64 zv = 0; dx = SPI_getbinval(tuple, tupdesc, 1, &isnull); dy = SPI_getbinval(tuple, tupdesc, 2, &isnull); zv = zcurve_fromXY(DatumGetInt64(dx), DatumGetInt64(dy)); // elog(INFO, "%ld %ld -> %ld", DatumGetInt64(dx), DatumGetInt64(dy), zv); ctx->cur_val_ = zv; SPI_cursor_close(portal); return 1; } SPI_cursor_close(portal); } return 0; } int run_interval_request_ii(interval_ctx_t *ctx, uint64 v0, uint64 v1) { Datum values[2]; /* key types to prepare execution plan */ Portal portal; int cnt = 0, i; values[0] = Int64GetDatum(v0); values[1] = Int64GetDatum(v1); // elog(INFO, "[%ld %ld]", v0, v1); if (ctx->fl_) fprintf(ctx->fl_, "EXPLAIN (ANALYZE,BUFFERS) select * from test_points where zcurve_val_from_xy(x, y) between %ld and %ld;\n", v0, v1); portal = SPI_cursor_open(NULL, ctx->cr_, values, NULL, true); if (NULL == portal) /* internal error */ elog(ERROR, "check_primary_key: SPI_cursor_open"); for (;;) { SPI_cursor_fetch(portal, true, 8); if (0 == SPI_processed || NULL == SPI_tuptable) break; { TupleDesc tupdesc = SPI_tuptable->tupdesc; for (i = 0; i < SPI_processed; i++) { HeapTuple tuple = SPI_tuptable->vals[i]; // elog(INFO, "%s, %s", SPI_getvalue(tuple, tupdesc, 1), SPI_getvalue(tuple, tupdesc, 2)); cnt++; } } } SPI_cursor_close(portal); return cnt; } PG_FUNCTION_INFO_V1(zcurve_oids_by_extent_ii); Datum zcurve_oids_by_extent_ii(PG_FUNCTION_ARGS) { uint64 x0 = PG_GETARG_INT64(0); uint64 y0 = PG_GETARG_INT64(1); uint64 x1 = PG_GETARG_INT64(2); uint64 y1 = PG_GETARG_INT64(3); uint64 *ids = NULL; int cnt = 0; int sz = 0, ix, iy; interval_ctx_t ctx; x0 = MIN(x0, s_maxx); y0 = MIN(y0, s_maxy); x1 = MIN(x1, s_maxx); y1 = MIN(y1, s_maxy); if (x0 > x1) elog(ERROR, "xmin > xmax"); if (y0 > y1) elog(ERROR, "ymin > ymax"); sz = (x1 - x0 + 1) * (y1 - y0 + 1); ids = (uint64*)palloc(sz * sizeof(uint64)); if (NULL == ids) /* internal error */ elog(ERROR, "can't alloc %d bytes in zcurve_oids_by_extent_ii", sz); for (ix = x0; ix <= x1; ix++) for (iy = y0; iy <= y1; iy++) { ids[cnt++] = zcurve_fromXY(ix, iy); } qsort (ids, sz, sizeof(*ids), compare_uint64); ctx.top_val_ = ids[sz - 1]; ctx.cur_val_ = 0; ctx.cr_ = NULL; ctx.probe_cr_ = NULL; ctx.fl_ = NULL;//fopen("/tmp/ttt.sql", "w"); cnt = 0; prep_interval_request_ii(&ctx); { int cur_start = 0; int ix; for (ix = cur_start + 1; ix < sz; ix++) { if (0 == probe_interval_request_ii(&ctx, ids[cur_start])) break; for (; cur_start < sz && ids[cur_start] < ctx.cur_val_; cur_start++); // if (ctx.cur_val_ != ids[cur_start]) // { // cur_start++; // continue; // } ix = cur_start + 1; if (ix >= sz) break; for (; ix < sz && ids[ix] == ids[ix - 1] + 1; ix++); //elog(INFO, "%d %d %d", ix, cur_start, sz); cnt += run_interval_request_ii(&ctx, ids[cur_start], ids[ix - 1]); cur_start = ix; } } if (ctx.fl_) fclose(ctx.fl_); fin_interval_request(NULL); pfree(ids); PG_RETURN_INT64(cnt); }
ç§ã¯ããã«æçš¿ããŸããããgithubã«ã¯æçš¿ããŠããŸãã ã³ãŒãã¯çŽç²ã«å®éšçãªãã®ã§ãããå®çšçãªäŸ¡å€ã¯ãããŸããã
PPSïŒãã®ä»äºãããããç§ãå±ãŸããŠããã
PostgresProã®çããã«æè¬ããŸãã
PPPSïŒ
ãããš
ããã§ç¶ã
ãŸã