63.2. ÐндекÑÑ GiST #
63.2.1. Ðведение #
GiST ÑаÑÑиÑÑовÑваеÑÑÑ ÐºÐ°Ðº «Generalized Search Tree» (ÐбобÑÑнное поиÑковое деÑево). ÐÑо ÑбаланÑиÑованнÑй иеÑаÑÑ Ð¸ÑеÑкий меÑод доÑÑÑпа, коÑоÑÑй пÑедÑÑавлÑÐµÑ Ñобой базовÑй Ñаблон, на оÑнове коÑоÑого могÑÑ ÑеализовÑваÑÑÑÑ Ð¿ÑоизволÑнÑе ÑÑ ÐµÐ¼Ñ Ð¸Ð½Ð´ÐµÐºÑаÑии. Ðа базе GiST могÑÑ Ð±ÑÑÑ ÑÐµÐ°Ð»Ð¸Ð·Ð¾Ð²Ð°Ð½Ñ B-деÑевÑÑ, R-деÑевÑÑ Ð¸ многие дÑÑгие ÑÑ ÐµÐ¼Ñ Ð¸Ð½Ð´ÐµÐºÑаÑии.
ÐлÑÑевÑм пÑеимÑÑеÑÑвом GiST ÑвлÑеÑÑÑ Ñо, ÑÑо он позволÑÐµÑ ÑазÑабаÑÑваÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ Ñ ÑооÑвеÑÑÑвÑÑÑими меÑодами доÑÑÑпа ÑкÑпеÑÑам в пÑедмеÑной облаÑÑи Ñипа даннÑÑ , а не ÑпеÑиалиÑÑам по СУÐÐ.
ÐÑедÑÑÐ°Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ð·Ð´ÐµÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ ÑаÑÑиÑно позаимÑÑвована Ñ ÑайÑа ÐÑоекÑа индекÑаÑии GiST ÐалиÑоÑнийÑкого ÑнивеÑÑиÑеÑа в ÐеÑкли и из диÑÑеÑÑаÑии ÐаÑÑÐµÐ»Ñ ÐоÑнакеÑа ÐеÑÐ¾Ð´Ñ Ð´Ð¾ÑÑÑпа Ð´Ð»Ñ Ð¡Ð£ÐÐ ÑледÑÑÑего поколениÑ. СопÑовождением ÑеализаÑии GiST в Postgres Pro в оÑновном занимаÑÑÑÑ Ð¤ÑÐ´Ð¾Ñ Ð¡Ð¸Ð³Ð°ÐµÐ² и Ðлег ÐаÑÑÑнов; дополниÑелÑнÑе ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ полÑÑиÑÑ Ð½Ð° Ð¸Ñ ÑайÑе.
63.2.2. ÐÑÑÑоеннÑе клаÑÑÑ Ð¾Ð¿ÐµÑаÑоÑов #
РбазовÑй диÑÑÑибÑÑив Postgres Pro вклÑÑÐµÐ½Ñ ÐºÐ»Ð°ÑÑÑ Ð¾Ð¿ÐµÑаÑоÑов GiST, пеÑеÑиÑленнÑе в ТаблиÑе 63.1. (ÐекоÑоÑÑе дополниÑелÑнÑе модÑли, опиÑаннÑе в ÐÑиложении F, добавлÑÑÑ Ð´ÑÑгие клаÑÑÑ Ð¾Ð¿ÐµÑаÑоÑов GiST.)
ТаблиÑа 63.1. ÐÑÑÑоеннÑе клаÑÑÑ Ð¾Ð¿ÐµÑаÑоÑов GiST
| ÐÐ¼Ñ | ÐндекÑиÑÑемÑе опеÑаÑоÑÑ | ÐпеÑаÑоÑÑ ÑпоÑÑдоÑÐ¸Ð²Ð°Ð½Ð¸Ñ |
|---|---|---|
box_ops | << (box, box) | <-> (box, point) |
&< (box, box) | ||
&& (box, box) | ||
&> (box, box) | ||
>> (box, box) | ||
~= (box, box) | ||
@> (box, box) | ||
<@ (box, box) | ||
&<| (box, box) | ||
<<| (box, box) | ||
|>> (box, box) | ||
|&> (box, box) | ||
circle_ops | << (circle, circle) | <-> (circle, point) |
&< (circle, circle) | ||
&> (circle, circle) | ||
>> (circle, circle) | ||
<@ (circle, circle) | ||
@> (circle, circle) | ||
~= (circle, circle) | ||
&& (circle, circle) | ||
|>> (circle, circle) | ||
<<| (circle, circle) | ||
&<| (circle, circle) | ||
|&> (circle, circle) | ||
inet_ops | << (inet, inet) | Â |
<<= (inet, inet) | ||
>> (inet, inet) | ||
>>= (inet, inet) | ||
= (inet, inet) | ||
<> (inet, inet) | ||
< (inet, inet) | ||
<= (inet, inet) | ||
> (inet, inet) | ||
>= (inet, inet) | ||
&& (inet, inet) | ||
multirange_ops | = (anymultirange, anymultirange) | Â |
&& (anymultirange, anymultirange) | ||
&& (anymultirange, anyrange) | ||
@> (anymultirange, anyelement) | ||
@> (anymultirange, anymultirange) | ||
@> (anymultirange, anyrange) | ||
<@ (anymultirange, anymultirange) | ||
<@ (anymultirange, anyrange) | ||
<< (anymultirange, anymultirange) | ||
<< (anymultirange, anyrange) | ||
>> (anymultirange, anymultirange) | ||
>> (anymultirange, anyrange) | ||
&< (anymultirange, anymultirange) | ||
&< (anymultirange, anyrange) | ||
&> (anymultirange, anymultirange) | ||
&> (anymultirange, anyrange) | ||
-|- (anymultirange, anymultirange) | ||
-|- (anymultirange, anyrange) | ||
point_ops | |>> (point, point) | <-> (point, point) |
<< (point, point) | ||
>> (point, point) | ||
<<| (point, point) | ||
~= (point, point) | ||
<@ (point, box) | ||
<@ (point, polygon) | ||
<@ (point, circle) | ||
poly_ops | << (polygon, polygon) | <-> (polygon, point) |
&< (polygon, polygon) | ||
&> (polygon, polygon) | ||
>> (polygon, polygon) | ||
<@ (polygon, polygon) | ||
@> (polygon, polygon) | ||
~= (polygon, polygon) | ||
&& (polygon, polygon) | ||
<<| (polygon, polygon) | ||
&<| (polygon, polygon) | ||
|&> (polygon, polygon) | ||
|>> (polygon, polygon) | ||
range_ops | = (anyrange, anyrange) | Â |
&& (anyrange, anyrange) | ||
&& (anyrange, anymultirange) | ||
@> (anyrange, anyelement) | ||
@> (anyrange, anyrange) | ||
@> (anyrange, anymultirange) | ||
<@ (anyrange, anyrange) | ||
<@ (anyrange, anymultirange) | ||
<< (anyrange, anyrange) | ||
<< (anyrange, anymultirange) | ||
>> (anyrange, anyrange) | ||
>> (anyrange, anymultirange) | ||
&< (anyrange, anyrange) | ||
&< (anyrange, anymultirange) | ||
&> (anyrange, anyrange) | ||
&> (anyrange, anymultirange) | ||
-|- (anyrange, anyrange) | ||
-|- (anyrange, anymultirange) | ||
tsquery_ops | <@ (tsquery, tsquery) | Â |
@> (tsquery, tsquery) | ||
tsvector_ops | @@ (tsvector, tsquery) | Â |
Ðо иÑÑоÑиÑеÑким пÑиÑинам клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов inet_ops не ÑвлÑеÑÑÑ ÐºÐ»Ð°ÑÑом по ÑмолÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ Ñипов inet и cidr. ЧÑÐ¾Ð±Ñ Ð¸ÑполÑзоваÑÑ ÐµÐ³Ð¾, ÑкажиÑе Ð¸Ð¼Ñ ÐºÐ»Ð°ÑÑа в CREATE INDEX, напÑимеÑ:
CREATE INDEX ON my_table USING GIST (my_inet_column inet_ops);
63.2.3. РаÑÑиÑÑемоÑÑÑ #
РеализаÑÐ¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ меÑода доÑÑÑпа индекÑа ÑÑадиÑионно бÑла болÑÑой и Ñложной задаÑей. ЧÑÐ¾Ð±Ñ ÐµÑ ÑеÑиÑÑ, Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ бÑло понимаÑÑ Ð²Ð½ÑÑÑеннее ÑÑÑÑойÑÑво Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ , в ÑаÑÑноÑÑи ÑабоÑÑ Ð¼ÐµÐ½ÐµÐ´Ð¶ÐµÑа блокиÑовок и жÑÑнала пÑедзапиÑи. Ðо Ñ Ð¸Ð½ÑеÑÑейÑом GiST, ÑеализÑÑÑим вÑÑокий ÑÑÐ¾Ð²ÐµÐ½Ñ Ð°Ð±ÑÑÑакÑии, ÑазÑабоÑÑик меÑода доÑÑÑпа должен ÑеализоваÑÑ ÑолÑко ÑмÑÑловое наполнение индекÑиÑÑемого Ñипа даннÑÑ . УÑÐ¾Ð²ÐµÐ½Ñ GiST беÑÑÑ Ð½Ð° ÑÐµÐ±Ñ Ð·Ð°Ð±Ð¾ÑÑ Ð¾ паÑаллелÑном доÑÑÑпе, поддеÑжке жÑÑнала и поиÑке в ÑÑÑÑкÑÑÑе деÑева.
ÐÑÑ ÑаÑÑиÑÑемоÑÑÑ Ð½Ðµ ÑледÑÐµÑ Ð¿ÑÑаÑÑ Ñ ÑаÑÑиÑÑемоÑÑÑÑ Ð´ÑÑгиÑ
ÑÑандаÑÑнÑÑ
деÑевÑев поиÑка в ÑмÑÑле поддеÑжки ÑазлиÑнÑÑ
Ñипов даннÑÑ
. ÐапÑимеÑ, Postgres Pro поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ ÑаÑÑиÑÑемоÑÑÑ B-деÑевÑев и индекÑов по Ñ
еÑÑ. ÐÑо ознаÑаеÑ, ÑÑо в Postgres Pro Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе поÑÑÑоиÑÑ B-деÑево или Ñ
еÑ-ÑаблиÑÑ Ð¿Ð¾ лÑÐ±Ð¾Ð¼Ñ Ð¶ÐµÐ»Ð°ÐµÐ¼Ð¾Ð¼Ñ ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ
. Ðо Ñакие B-деÑевÑÑ Ð±ÑдÑÑ Ð¿Ð¾Ð´Ð´ÐµÑживаÑÑ ÑолÑко пÑедикаÑÑ ÑÑавнений (<, =, >), а индекÑÑ Ð¿Ð¾ Ñ
еÑÑ ÑолÑко запÑоÑÑ Ñ ÑавенÑÑвом.
ÐоÑÑомÑ, еÑли Ð²Ñ Ð¿ÑоиндекÑиÑÑеÑе в Postgres Pro в B-деÑеве, напÑимеÑ, коллекÑÐ¸Ñ Ð¸Ð·Ð¾Ð±Ñажений, Ð²Ñ ÑможеÑе вÑполнÑÑÑ ÑолÑко пÑовеÑки вида «ÑÐ°Ð²Ð½Ñ Ð»Ð¸ изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ X и Y», «менÑÑе ли изобÑажение X изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Y» и «болÑÑе ли изобÑажение X изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Y». ÐÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾, в завиÑимоÑÑи Ð¾Ñ Ñого, как Ð²Ñ Ð¾Ð¿ÑеделиÑе опеÑаÑии «Ñавно», «менÑÑе» и «болÑÑе». Ðднако иÑполÑзÑÑ Ð¸Ð½Ð´ÐµÐºÑ Ð½Ð° базе GiST, возможно ÑдовлеÑвоÑÑÑÑ Ð¸ запÑоÑÑ Ð¸Ð· пÑедмеÑной облаÑÑи, напÑимеÑ, «найÑи вÑе изобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð»Ð¾Ñадей» или «найÑи вÑе пеÑеÑвеÑеннÑе изобÑажениÑ».
ÐÑÑ, ÑÑо нÑжно, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ ÑабоÑаÑÑий меÑод доÑÑÑпа GiST â ÑÑо ÑеализоваÑÑ Ð½ÐµÑколÑко меÑодов, опÑеделÑÑÑÐ¸Ñ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ðµ клÑÑей в деÑеве. ÐонеÑно, ÑÑи меÑÐ¾Ð´Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð´Ð¾Ð²Ð¾Ð»Ñно изоÑÑÑннÑми, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð´Ð´ÐµÑживаÑÑ Ð¸Ð·Ð¾ÑÑÑннÑе запÑоÑÑ, но Ð´Ð»Ñ Ð²ÑÐµÑ ÑÑандаÑÑнÑÑ Ð·Ð°Ð¿ÑоÑов (B-деÑевÑев, R-деÑевÑев и Ñ. д.) они оÑноÑиÑелÑно пÑоÑÑÑ. Словом, GiST ÑоÑеÑÐ°ÐµÑ ÑаÑÑиÑÑемоÑÑÑ Ñ ÑнивеÑÑалÑноÑÑÑÑ, повÑоÑнÑм иÑполÑзованием кода и аккÑÑаÑнÑм инÑеÑÑейÑом.
ÐлаÑÑ Ð¾Ð¿ÐµÑаÑоÑов индекÑа GiST должен пÑедоÑÑавиÑÑ Ð¿ÑÑÑ Ð¼ÐµÑодов и Ð¼Ð¾Ð¶ÐµÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑно пÑедоÑÑавлÑÑÑ ÐµÑÑ ÑемÑ. ÐоÑÑекÑноÑÑÑ Ð¸Ð½Ð´ÐµÐºÑа обеÑпеÑиваеÑÑÑ ÑеализаÑией меÑодов same, consistent и union, а его ÑÑÑекÑивноÑÑÑ (по ÑазмеÑÑ Ð¸ ÑкоÑоÑÑи) бÑÐ´ÐµÑ Ð·Ð°Ð²Ð¸ÑеÑÑ Ð¾Ñ Ð¼ÐµÑодов penalty и picksplit. Ðва необÑзаÑелÑнÑÑ
меÑода, compress и decompress, позволÑÑÑ ÑеализоваÑÑ Ð²Ð½ÑÑÑеннее пÑедÑÑавление даннÑÑ
деÑева, не ÑовпадаÑÑее Ñ Ñипом индекÑиÑÑемÑÑ
даннÑÑ
. ÐаннÑе лиÑÑÑев индекÑа Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð¸Ð½Ð´ÐµÐºÑиÑÑемого Ñипа, Ñогда как в оÑÑалÑнÑÑ
ÑзлаÑ
деÑева могÑÑ Ð±ÑÑÑ Ð¿ÑоизволÑнÑе ÑÑÑÑкÑÑÑÑ C (но пÑи ÑÑом Ð´Ð¾Ð»Ð¶Ð½Ñ ÑоблÑдаÑÑÑÑ Ð¿Ñавила, пÑедÑÑвлÑемÑе Postgres Pro к Ñипам даннÑÑ
; пÑоÑиÑайÑе о varlena Ð´Ð»Ñ Ð´Ð°Ð½Ð½ÑÑ
пеÑеменного ÑазмеÑа). ÐÑли внÑÑÑенний Ñип даннÑÑ
деÑева ÑÑÑеÑÑвÑÐµÑ Ð½Ð° ÑÑовне SQL, в команде CREATE OPERATOR CLASS можно иÑполÑзоваÑÑ Ñказание STORAGE. ÐеобÑзаÑелÑнÑй воÑÑмой меÑод distance нÑжно ÑеализоваÑÑ, ÑолÑко еÑли клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов Ð¶ÐµÐ»Ð°ÐµÑ Ð¿Ð¾Ð´Ð´ÐµÑживаÑÑ ÑпоÑÑдоÑеннÑе ÑканиÑÐ¾Ð²Ð°Ð½Ð¸Ñ (поиÑк ближайÑиÑ
ÑоÑедей). ÐеобÑзаÑелÑнÑй девÑÑÑй меÑод fetch ÑÑебÑеÑÑÑ, еÑли клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов должен поддеÑживаÑÑ ÑканиÑование ÑолÑко индекÑа и пÑи ÑÑом пÑедоÑÑавлÑеÑÑÑ Ð¼ÐµÑод compress. ÐеобÑзаÑелÑнÑй деÑÑÑÑй меÑод options необÑ
одим, еÑли клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов ÑодеÑÐ¶Ð¸Ñ Ð¾Ð¿ÑеделÑемÑе полÑзоваÑелем паÑамеÑÑÑ. ÐеобÑзаÑелÑнÑй одиннадÑаÑÑй меÑод sortsupport иÑполÑзÑеÑÑÑ Ð´Ð»Ñ ÑÑкоÑÐµÐ½Ð¸Ñ Ð¿Ð¾ÑÑÑÐ¾ÐµÐ½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа GiST. ÐеобÑзаÑелÑнÑй двенадÑаÑÑй меÑод stratnum иÑполÑзÑеÑÑÑ Ð´Ð»Ñ Ð¿ÑеобÑÐ°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñипов ÑÑавнений в номеÑа ÑÑÑаÑегий, иÑполÑзÑемÑÑ
клаÑÑом опеÑаÑоÑов. ÐÑо позволÑÐµÑ ÐºÐ¾Ð´Ñ ÑдÑа наÑ
одиÑÑ Ð¾Ð¿ÐµÑаÑоÑÑ Ð´Ð»Ñ Ð¸Ð½Ð´ÐµÐºÑов Ñ ÑемпоÑалÑнÑми огÑаниÑениÑми.
consistentÐÐ»Ñ Ð¿ÐµÑеданной запиÑи индекÑа
pи знаÑÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑоÑаqÑÑа ÑÑнкÑÐ¸Ñ Ð¾Ð¿ÑеделÑеÑ, ÑвлÑеÑÑÑ Ð»Ð¸ запиÑÑ Ð¸Ð½Ð´ÐµÐºÑа «ÑооÑвеÑÑÑвÑÑÑей» запÑоÑÑ; Ñо еÑÑÑ, Ð¼Ð¾Ð¶ÐµÑ Ð»Ð¸ пÑÐµÐ´Ð¸ÐºÐ°Ñ Â«Ð¸Ð½Ð´ÐµÐºÑиÑованнÑй_ÑÑолбеÑиндекÑиÑÑемÑй_опеÑаÑоÑq» ÑдовлеÑвоÑÑÑÑÑÑ Ð´Ð»Ñ ÐºÐ°ÐºÐ¾Ð¹-либо ÑÑÑоки, пÑедÑÑавленной данной запиÑÑÑ Ð¸Ð½Ð´ÐµÐºÑа? ÐÐ»Ñ Ð·Ð°Ð¿Ð¸Ñей на ÑÑовне лиÑÑÑев ÑÑо ÑавноÑилÑно пÑовеÑке индекÑиÑÑемого ÑÑловиÑ, Ñогда как Ð´Ð»Ñ Ð²Ð½ÑÑÑеннего Ñзла деÑева ÑÑебÑеÑÑÑ Ð¾Ð¿ÑеделиÑÑ, нÑжно ли ÑканиÑоваÑÑ Ð¿Ð¾Ð´Ð´ÐµÑево индекÑа, оÑноÑÑÑееÑÑ Ðº Ð´Ð°Ð½Ð½Ð¾Ð¼Ñ ÑзлÑ. Ðогда ÑезÑлÑÑаÑtrue, Ñакже должен возвÑаÑаÑÑÑÑ Ñлагrecheck, показÑваÑÑий, ÑоÑно ли ÑдовлеÑвоÑÑеÑÑÑ Ð¿ÑÐµÐ´Ð¸ÐºÐ°Ñ Ð¸Ð»Ð¸ ÑÑо лиÑÑ Ð¿Ð¾ÑенÑиалÑно возможно. ÐÑлиrecheck=false, ÑÑо ознаÑаеÑ, ÑÑо Ð¸Ð½Ð´ÐµÐºÑ Ð¿ÑовеÑил ÑÑловие пÑедикаÑа в ÑоÑноÑÑи, Ñогда как пÑиrecheck=trueпÑовеÑÑÐµÐ¼Ð°Ñ ÑÑÑока бÑÐ´ÐµÑ ÑолÑко кандидаÑом на Ñовпадение. Ð ÑÑом ÑлÑÑае ÑиÑÑема авÑомаÑиÑеÑки пеÑепÑовеÑиÑиндекÑиÑÑемÑй_опеÑаÑоÑÑ Ð´ÐµÐ¹ÑÑвиÑелÑнÑм знаÑением ÑÑÑоки, ÑÑÐ¾Ð±Ñ Ð¾ÐºÐ¾Ð½ÑаÑелÑно опÑеделиÑÑ, ÑооÑвеÑÑÑвÑÐµÑ Ð»Ð¸ оно запÑоÑÑ. ÐлагодаÑÑ ÑÑÐ¾Ð¼Ñ GiST поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ Ð¸Ð½Ð´ÐµÐºÑÑ ÐºÐ°Ðº ÑоÑной, Ñак и неÑоÑной ÑÑÑÑкÑÑÑÑ.Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ð¿ÑимеÑно Ñак:
CREATE OR REPLACE FUNCTION my_consistent(internal, data_type, smallint, oid, internal) RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
Ð ÑооÑвеÑÑÑвÑÑÑий код в модÑле C Ð¼Ð¾Ð¶ÐµÑ ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_consistent); Datum my_consistent(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); data_type *query = PG_GETARG_DATA_TYPE_P(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); data_type *key = DatumGetDataType(entry->key); bool retval; /* * ÐпÑеделиÑÑ Ð²Ð¾Ð·Ð²ÑаÑаемое знаÑение как ÑÑнкÑÐ¸Ñ ÑÑÑаÑегии, клÑÑа и запÑоÑа. * * ÐÑзовиÑе GIST_LEAF(entry), ÑÑÐ¾Ð±Ñ ÑзнаÑÑ ÑекÑÑÑÑ Ð¿Ð¾Ð·Ð¸ÑÐ¸Ñ Ð² деÑеве индекÑа, * ÑÑо Ñдобно, напÑÐ¸Ð¼ÐµÑ Ð´Ð»Ñ Ð¿Ð¾Ð´Ð´ÐµÑжки опеÑаÑоÑа = (Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пÑовеÑиÑÑ * ÑавенÑÑво в лиÑÑÑÑÑ Ð´ÐµÑева и непÑÑÑое пеÑеÑеÑение в оÑÑалÑнÑÑ * ÑÐ·Ð»Ð°Ñ ). */ *recheck = true; /* или false, еÑли пÑовеÑка ÑоÑÐ½Ð°Ñ */ PG_RETURN_BOOL(retval); }ÐдеÑÑ
keyâ ÑÑо ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð² индекÑе, аqueryâ знаÑение, иÑкомое в индекÑе. ÐаÑамеÑÑStrategyNumberпоказÑваеÑ, какой опеÑаÑÐ¾Ñ Ð¸Ð· клаÑÑа опеÑаÑоÑов пÑименÑеÑÑÑ â он ÑооÑвеÑÑÑвÑÐµÑ Ð¾Ð´Ð½Ð¾Ð¼Ñ Ð¸Ð· номеÑов опеÑаÑоÑов, заданнÑÑ Ð² командеCREATE OPERATOR CLASS.РзавиÑимоÑÑи Ð¾Ñ Ñого, какие опеÑаÑоÑÑ Ð²ÐºÐ»ÑÑÐµÐ½Ñ Ð² клаÑÑ, Ñип даннÑÑ
queryÐ¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑазнÑм Ð´Ð»Ñ ÑазнÑÑ Ð¾Ð¿ÐµÑаÑоÑов, Ñак как ÑÑо бÑÐ´ÐµÑ ÑÐ¾Ñ Ñип, ÑÑо ÑигÑÑиÑÑÐµÑ Ð² пÑавой ÑаÑÑи опеÑаÑоÑа, и он Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑлиÑаÑÑÑÑ Ð¾Ñ Ð¸Ð½Ð´ÐµÐºÑиÑÑемого Ñипа даннÑÑ , ÑигÑÑиÑÑÑÑего Ñлева. (Рпоказанном вÑÑе Ñаблоне пÑедполагаеÑÑÑ, ÑÑо допÑÑкаеÑÑÑ ÑолÑко один Ñип; в пÑоÑивном ÑлÑÑае полÑÑение знаÑениÑqueryзавиÑело Ð±Ñ Ð¾Ñ Ð¾Ð¿ÐµÑаÑоÑа.) Ð SQL-обÑÑвлении ÑÑнкÑииconsistentÐ´Ð»Ñ Ð°ÑгÑменÑаqueryÑекомендÑеÑÑÑ ÑÑÑановиÑÑ Ð¸Ð½Ð´ÐµÐºÑиÑованнÑй Ñип данного клаÑÑа опеÑаÑоÑов, Ñ Ð¾ÑÑ ÑакÑиÑеÑкий Ñип Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÐºÐ°ÐºÐ¸Ð¼-Ñо дÑÑгим, в завиÑимоÑÑи Ð¾Ñ Ð¾Ð¿ÐµÑаÑоÑа.unionÐÑÐ¾Ñ Ð¼ÐµÑод конÑолидиÑÑÐµÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð² деÑеве. ÐолÑÑив Ð½Ð°Ð±Ð¾Ñ Ð·Ð°Ð¿Ð¸Ñей, он должен ÑгенеÑиÑоваÑÑ Ð² индекÑе новÑÑ Ð·Ð°Ð¿Ð¸ÑÑ, пÑедÑÑавлÑÑÑие вÑе ÑÑи запиÑи.
Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_union(internal, internal) RETURNS storage_type AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
Ð ÑооÑвеÑÑÑвÑÑÑий код в модÑле C должен ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_union); Datum my_union(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GISTENTRY *ent = entryvec->vector; data_type *out, *tmp, *old; int numranges, i = 0; numranges = entryvec->n; tmp = DatumGetDataType(ent[0].key); out = tmp; if (numranges == 1) { out = data_type_deep_copy(tmp); PG_RETURN_DATA_TYPE_P(out); } for (i = 1; i < numranges; i++) { old = out; tmp = DatumGetDataType(ent[i].key); out = my_union_implementation(out, tmp); } PG_RETURN_DATA_TYPE_P(out); }Ðак можно замеÑиÑÑ, в ÑÑом Ñаблоне Ð¼Ñ Ð¸Ð¼ÐµÐµÐ¼ дело Ñ Ñипом даннÑÑ , Ð´Ð»Ñ ÐºÐ¾ÑоÑого
union(X, Y, Z) = union(union(X, Y), Z). ÐоÑÑаÑоÑно пÑоÑÑо можно поддеÑжаÑÑ Ð¸ Ñакие ÑÐ¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ , Ð´Ð»Ñ ÐºÐ¾ÑоÑÑÑ ÑÑо не вÑполнÑеÑÑÑ, Ñеализовав ÑооÑвеÑÑÑвÑÑÑий алгоÑиÑм обÑÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð² ÑÑом опоÑном меÑоде GiST.РезÑлÑÑаÑом ÑÑнкÑии
unionдолжно бÑÑÑ Ð·Ð½Ð°Ñение Ñипа Ñ ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа, каким Ð±Ñ Ð¾Ð½ ни бÑл (он Ð¼Ð¾Ð¶ÐµÑ ÑовпадаÑÑ Ñ Ñипом индекÑиÑованного ÑÑолбÑа, а Ð¼Ð¾Ð¶ÐµÑ Ð¸ оÑлиÑаÑÑÑÑ Ð¾Ñ Ð½ÐµÐ³Ð¾). ФÑнкÑиÑ, ÑеализÑÑÑаÑunion, должна возвÑаÑаÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° памÑÑÑ, вÑделеннÑÑ Ð²Ñзовомpalloc(). Ðна не Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑоÑÑо веÑнÑÑÑ Ð¿Ð¾Ð»ÑÑенное знаÑение как еÑÑÑ, даже еÑли оно Ð¸Ð¼ÐµÐµÑ ÑÐ¾Ñ Ð¶Ðµ Ñип.Ðак показано вÑÑе, пеÑвÑй аÑгÑменÑ
internalÑÑнкÑииunionна Ñамом деле пÑедÑÑавлÑÐµÑ ÑказаÑелÑGistEntryVector. Ðо вÑоÑом аÑгÑменÑе (его можно игноÑиÑоваÑÑ) пеÑедаÑÑÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° ÑелоÑиÑленнÑÑ Ð¿ÐµÑеменнÑÑ. (РанÑÑе ÑÑебовалоÑÑ, ÑÑÐ¾Ð±Ñ ÑÑнкÑиÑunionÑÐ¾Ñ ÑанÑла в ÑÑой пеÑеменной ÑÐ°Ð·Ð¼ÐµÑ ÑезÑлÑÑиÑÑÑÑего знаÑениÑ, но ÑепеÑÑ Ñакого ÑÑÐµÐ±Ð¾Ð²Ð°Ð½Ð¸Ñ Ð½ÐµÑ.)compressÐÑеобÑазÑÐµÑ ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð´Ð°Ð½Ð½ÑÑ Ð² ÑоÑмаÑ, Ð¿Ð¾Ð´Ñ Ð¾Ð´ÑÑий Ð´Ð»Ñ ÑизиÑеÑкого Ñ ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð² ÑÑÑаниÑе индекÑа. ÐÑли меÑод
compressне Ñеализован, ÑлеменÑÑ Ð´Ð°Ð½Ð½ÑÑ Ñ ÑанÑÑÑÑ Ð² индекÑе без модиÑикаÑии.Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_compress(internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
Ð ÑооÑвеÑÑÑвÑÑÑий код в модÑле C должен ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_compress); Datum my_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval; if (entry->leafkey) { /* замениÑÑ entry->key ÑжаÑой веÑÑией */ compressed_data_type *compressed_data = palloc(sizeof(compressed_data_type)); /* заполниÑÑ *compressed_data из entry->key ... */ retval = palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(compressed_data), entry->rel, entry->page, entry->offset, FALSE); } else { /* обÑÑно Ñ Ð·Ð°Ð¿Ð¸ÑÑми внÑÑÑÐµÐ½Ð½Ð¸Ñ Ñзлов ниÑего делаÑÑ Ð½Ðµ нÑжно */ retval = entry; } PG_RETURN_POINTER(retval); }РазÑмееÑÑÑ,
compressed_data_type(Ñип ÑжаÑÑÑ Ð´Ð°Ð½Ð½ÑÑ ) нÑжно пÑивеÑÑи к нÑÐ¶Ð½Ð¾Ð¼Ñ ÑипÑ, пÑи пÑеобÑазовании в коÑоÑÑй бÑдÑÑ ÑжимаÑÑÑÑ ÑÐ·Ð»Ñ Ð½Ð° ÑÑовне лиÑÑÑев.decompressÐÑеобÑазÑÐµÑ ÑÐ¾Ñ ÑанÑнное пÑедÑÑавление даннÑÑ Ð² ÑоÑмаÑ, Ñ ÐºÐ¾ÑоÑÑм ÑмогÑÑ ÑабоÑаÑÑ Ð´ÑÑгие меÑÐ¾Ð´Ñ GiST в клаÑÑе опеÑаÑоÑов. ÐÑли меÑод
decompressопÑÑкаеÑÑÑ, подÑазÑмеваеÑÑÑ, ÑÑо ÑÑи меÑÐ¾Ð´Ñ Ð¼Ð¾Ð³ÑÑ ÑабоÑаÑÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно Ñ ÑоÑмаÑом Ñ ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½ÑÑ . (ÐеÑодdecompressне обÑзаÑелÑно бÑÐ´ÐµÑ Ð¾Ð±ÑаÑнÑм кcompress; в ÑаÑÑноÑÑи, еÑли ÑÑнкÑиÑcompressÑÐ¾Ñ ÑанÑÐµÑ Ð´Ð°Ð½Ð½Ñе Ñ Ð¿Ð¾ÑеÑÑми,decompressне ÑÐ¼Ð¾Ð¶ÐµÑ Ð²Ð¾ÑÑÑановиÑÑ Ð² ÑоÑноÑÑи иÑÑ Ð¾Ð´Ð½Ñе даннÑе. ÐоÑÑÐ¾Ð¼Ñ Ð¼ÐµÑодdecompressв обÑем ÑлÑÑае неÑавнознаÑенfetch, Ñак как дÑÑгим меÑодам GiST Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ поÑÑебоваÑÑÑÑ Ð²Ð¾ÑÑÑанавливаÑÑ Ð´Ð°Ð½Ð½Ñе полноÑÑÑÑ.)Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_decompress(internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
Ð ÑооÑвеÑÑÑвÑÑÑий код в модÑле C должен ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_decompress); Datum my_decompress(PG_FUNCTION_ARGS) { PG_RETURN_POINTER(PG_GETARG_POINTER(0)); }ÐÑÐ¾Ñ Ñаблон Ð¿Ð¾Ð´Ñ Ð¾Ð´Ð¸Ñ Ð´Ð»Ñ ÑлÑÑаÑ, когда пÑеобÑазовÑваÑÑ Ð´Ð°Ð½Ð½Ñе не нÑжно. (Ðо, ÑазÑмееÑÑÑ, еÑÑ Ð¿ÑоÑе и в болÑÑинÑÑве ÑлÑÑаев ÑекомендÑеÑÑÑ Ð²Ð¾Ð²Ñе опÑÑÑиÑÑ ÑÑÐ¾Ñ Ð¼ÐµÑод.)
penaltyÐозвÑаÑÐ°ÐµÑ Ð·Ð½Ð°Ñение, вÑÑажаÑÑее «ÑÑоимоÑÑÑ» Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð¹ запиÑи в конкÑеÑнÑÑ Ð²ÐµÑÐ²Ñ Ð´ÐµÑева. ÐлеменÑÑ Ð±ÑдÑÑ Ð²ÑÑавлÑÑÑÑÑ Ð¿Ð¾ ÑÐ¾Ð¼Ñ Ð½Ð°Ð¿ÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð² деÑеве, Ð´Ð»Ñ ÐºÐ¾ÑоÑого знаÑение
penaltyминималÑно. РезÑлÑÑаÑÑpenaltyÐ´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð½ÐµÐ¾ÑÑиÑаÑелÑнÑми; еÑли возвÑаÑаеÑÑÑ Ð¾ÑÑиÑаÑелÑное знаÑение, оно воÑпÑинимаеÑÑÑ ÐºÐ°Ðº нолÑ.Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_penalty(internal, internal, internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C STRICT; -- в некоÑоÑÑÑ ÑлÑÑаÑÑ ÑÑнкÑии ÑÑоимоÑÑи не Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ ÑÑÑогими
Ð ÑооÑвеÑÑÑвÑÑÑий код в модÑле C Ð¼Ð¾Ð¶ÐµÑ ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_penalty); Datum my_penalty(PG_FUNCTION_ARGS) { GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); float *penalty = (float *) PG_GETARG_POINTER(2); data_type *orig = DatumGetDataType(origentry->key); data_type *new = DatumGetDataType(newentry->key); *penalty = my_penalty_implementation(orig, new); PG_RETURN_POINTER(penalty); }Ðо иÑÑоÑиÑеÑким пÑиÑинам ÑÑнкÑиÑ
penaltyне пÑоÑÑо возвÑаÑÐ°ÐµÑ ÑезÑлÑÑÐ°Ñ Ñипаfloat; вмеÑÑо ÑÑого она должна ÑÐ¾Ñ ÑаниÑÑ ÐµÐ³Ð¾ знаÑение по адÑеÑÑ, ÑÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð¼Ñ ÑÑеÑÑим аÑгÑменÑом. СобÑÑвенно возвÑаÑаемое знаÑение игноÑиÑÑеÑÑÑ, Ñ Ð¾ÑÑ Ð² нÑм пÑинÑÑо возвÑаÑаÑÑ ÑÑÐ¾Ñ Ð¶Ðµ адÑеÑ.ФÑнкÑиÑ
penaltyважна Ð´Ð»Ñ Ñ Ð¾ÑоÑей пÑоизводиÑелÑноÑÑи индекÑа. Ðна бÑÐ´ÐµÑ Ð²ÑзÑваÑÑÑÑ Ð²Ð¾ вÑÐµÐ¼Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñи, ÑÑÐ¾Ð±Ñ Ð²ÑбÑаÑÑ Ð²ÐµÑÐ²Ñ Ð´Ð»Ñ Ð´Ð°Ð»ÑнейÑего движениÑ, когда в деÑево нÑжно добавиÑÑ Ð½Ð¾Ð²Ñй ÑлеменÑ. ÐÑо Ð¸Ð¼ÐµÐµÑ Ð·Ð½Ð°Ñение во вÑÐµÐ¼Ñ Ð·Ð°Ð¿ÑоÑа, Ñак как Ñем более ÑбаланÑиÑован индекÑ, Ñем бÑÑÑÑее бÑÐ´ÐµÑ Ð¿Ð¾Ð¸Ñк в нÑм.picksplitÐогда Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ ÑазделиÑÑ ÑÑÑаниÑÑ Ð¸Ð½Ð´ÐµÐºÑа, ÑÑа ÑÑнкÑÐ¸Ñ ÑеÑаеÑ, какие запиÑи Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¾ÑÑаÑÑÑÑ Ð² ÑÑаÑой ÑÑÑаниÑе, а какие нÑжно пеÑенеÑÑи в новÑÑ.
Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_picksplit(internal, internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
Ð ÑооÑвеÑÑÑвÑÑÑий код в модÑле C Ð¼Ð¾Ð¶ÐµÑ ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_picksplit); Datum my_picksplit(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); OffsetNumber maxoff = entryvec->n - 1; GISTENTRY *ent = entryvec->vector; int i, nbytes; OffsetNumber *left, *right; data_type *tmp_union; data_type *unionL; data_type *unionR; GISTENTRY **raw_entryvec; maxoff = entryvec->n - 1; nbytes = (maxoff + 1) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); left = v->spl_left; v->spl_nleft = 0; v->spl_right = (OffsetNumber *) palloc(nbytes); right = v->spl_right; v->spl_nright = 0; unionL = NULL; unionR = NULL; /* ÐниÑиализиÑоваÑÑ ÑиÑÑÑй векÑÐ¾Ñ Ð·Ð°Ð¿Ð¸Ñи. */ raw_entryvec = (GISTENTRY **) malloc(entryvec->n * sizeof(void *)); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) raw_entryvec[i] = &(entryvec->vector[i]); for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) { int real_index = raw_entryvec[i] - entryvec->vector; tmp_union = DatumGetDataType(entryvec->vector[real_index].key); Assert(tmp_union != NULL); /* * ÐÑбÑаÑÑ, кÑда помеÑаÑÑ Ð·Ð°Ð¿Ð¸Ñи индекÑа и измениÑÑ unionL и unionR * ÑооÑвеÑÑÑвенно. ÐобавиÑÑ Ð·Ð°Ð¿Ð¸Ñи в v->spl_left или * v->spl_right и ÑвелиÑиÑÑ ÑÑÑÑÑики. */ if (my_choice_is_left(unionL, curl, unionR, curr)) { if (unionL == NULL) unionL = tmp_union; else unionL = my_union_implementation(unionL, tmp_union); *left = real_index; ++left; ++(v->spl_nleft); } else { /* * То же Ñамое Ñ Ð¿Ñавой ÑÑоÑоной */ } } v->spl_ldatum = DataTypeGetDatum(unionL); v->spl_rdatum = DataTypeGetDatum(unionR); PG_RETURN_POINTER(v); }ÐамеÑÑÑе, ÑÑо ÑезÑлÑÑÐ°Ñ ÑÑнкÑии
picksplitдоÑÑавлÑеÑÑÑ ÑеÑез полÑÑеннÑÑ Ð½Ð° Ð²Ñ Ð¾Ð´ ÑÑÑÑкÑÑÑÑv. СобÑÑвенно возвÑаÑаемое знаÑение игноÑиÑÑеÑÑÑ, Ñ Ð¾ÑÑ Ð² нÑм пÑинÑÑо возвÑаÑаÑÑ Ð°Ð´ÑеÑv.Ðак и
penalty, ÑÑнкÑиÑpicksplitважна Ð´Ð»Ñ Ñ Ð¾ÑоÑей пÑоизводиÑелÑноÑÑи индекÑа. СложноÑÑÑ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð±ÑÑÑÑодейÑÑвÑÑÑÐ¸Ñ Ð¸Ð½Ð´ÐµÐºÑов GiST заклÑÑаеÑÑÑ ÐºÐ°Ðº Ñаз в ÑазÑабоÑке Ð¿Ð¾Ð´Ñ Ð¾Ð´ÑÑÐ¸Ñ ÑеализаÑийpenaltyиpicksplit.sameÐозвÑаÑÐ°ÐµÑ true, еÑли два ÑлеменÑа индекÑа ÑавнÑ, и false в пÑоÑивном ÑлÑÑае. («ÐÐ»ÐµÐ¼ÐµÐ½Ñ Ð¸Ð½Ð´ÐµÐºÑа» â ÑÑо знаÑение Ñипа Ñ ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа, а не обÑзаÑелÑно иÑÑ Ð¾Ð´Ð½Ð¾Ð³Ð¾ Ñипа индекÑиÑÑемого ÑÑолбÑа.)
Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_same(storage_type, storage_type, internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
Ð ÑооÑвеÑÑÑвÑÑÑий код в модÑле C Ð¼Ð¾Ð¶ÐµÑ ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_same); Datum my_same(PG_FUNCTION_ARGS) { prefix_range *v1 = PG_GETARG_PREFIX_RANGE_P(0); prefix_range *v2 = PG_GETARG_PREFIX_RANGE_P(1); bool *result = (bool *) PG_GETARG_POINTER(2); *result = my_eq(v1, v2); PG_RETURN_POINTER(result); }Ðо иÑÑоÑиÑеÑким пÑиÑинам ÑÑнкÑиÑ
sameне пÑоÑÑо возвÑаÑÐ°ÐµÑ ÑезÑлÑÑÐ°Ñ Ð±Ñлевого Ñипа; вмеÑÑо ÑÑого она должна ÑÐ¾Ñ ÑаниÑÑ Ñлаг по адÑеÑÑ, ÑÐºÐ°Ð·Ð°Ð½Ð½Ð¾Ð¼Ñ ÑÑеÑÑим аÑгÑменÑом. СобÑÑвенно возвÑаÑаемое знаÑение игноÑиÑÑеÑÑÑ, Ñ Ð¾ÑÑ Ð² нÑм пÑинÑÑо возвÑаÑаÑÑ ÑÑÐ¾Ñ Ð¶Ðµ адÑеÑ.distanceÐÐ»Ñ Ð¿ÐµÑеданной запиÑи индекÑа
pи знаÑÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑоÑаqÑÑа ÑÑнкÑÐ¸Ñ Ð¾Ð¿ÑеделÑÐµÑ Â«Ð´Ð¸ÑÑанÑиÑ» Ð¾Ñ Ð·Ð°Ð¿Ð¸Ñи индекÑа до знаÑÐµÐ½Ð¸Ñ Ð² запÑоÑе. ÐÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° бÑÑÑ Ð¿ÑедÑÑавлена, еÑли клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов ÑодеÑÐ¶Ð¸Ñ ÐºÐ°ÐºÐ¸Ðµ-либо опеÑаÑоÑÑ ÑпоÑÑдоÑиваниÑ. ÐапÑÐ¾Ñ Ñ Ð¾Ð¿ÐµÑаÑоÑом ÑпоÑÑдоÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð±ÑÐ´ÐµÑ Ð²ÑполнÑÑÑÑÑ Ñак, ÑÑÐ¾Ð±Ñ Ð·Ð°Ð¿Ð¸Ñи индекÑа Ñ Ð½Ð°Ð¸Ð¼ÐµÐ½ÑÑей «диÑÑанÑией» возвÑаÑалиÑÑ Ð¿ÐµÑвÑми, Ñак ÑÑо ÑезÑлÑÑаÑÑ Ð´Ð¾Ð»Ð¶Ð½Ñ ÑоглаÑовÑваÑÑÑÑ Ñо ÑмÑÑловÑм знаÑением опеÑаÑоÑа. ÐÐ»Ñ Ð·Ð°Ð¿Ð¸Ñи на ÑÑовне лиÑÑÑев ÑезÑлÑÑÐ°Ñ Ð¿ÑедÑÑавлÑÐµÑ ÑолÑко диÑÑанÑÐ¸Ñ Ð´Ð¾ ÑÑой запиÑи, а Ð´Ð»Ñ Ð²Ð½ÑÑÑеннего Ñзла деÑева ÑÑо бÑÐ´ÐµÑ Ð¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑÐ½Ð°Ñ Ð´Ð¸ÑÑанÑиÑ, коÑоÑÐ°Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¿Ð¾Ð»ÑÑена ÑÑеди вÑÐµÑ ÐµÐ³Ð¾ поÑомков.Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_distance(internal, data_type, smallint, oid, internal) RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
Ð ÑооÑвеÑÑÑвÑÑÑий код в модÑле C должен ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_distance); Datum my_distance(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); data_type *query = PG_GETARG_DATA_TYPE_P(1); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); /* Oid subtype = PG_GETARG_OID(3); */ /* bool *recheck = (bool *) PG_GETARG_POINTER(4); */ data_type *key = DatumGetDataType(entry->key); double retval; /* * опÑеделиÑÑ Ð²Ð¾Ð·Ð²ÑаÑаемое знаÑение как ÑÑнкÑÐ¸Ñ ÑÑÑаÑегии, клÑÑа и запÑоÑа. */ PG_RETURN_FLOAT8(retval); }ФÑнкÑии
distanceпеÑедаÑÑÑÑ Ñе же аÑгÑменÑÑ, ÑÑо и ÑÑнкÑииconsistent.ÐÑи опÑеделении диÑÑанÑии допÑÑкаеÑÑÑ Ð½ÐµÐºÐ¾ÑоÑÐ°Ñ Ð½ÐµÑоÑноÑÑÑ, еÑли ÑезÑлÑÑÐ°Ñ Ð½Ð¸ÐºÐ¾Ð³Ð´Ð° не бÑÐ´ÐµÑ Ð¿ÑевÑÑаÑÑ Ð´ÐµÐ¹ÑÑвиÑелÑнÑÑ Ð´Ð¸ÑÑанÑÐ¸Ñ Ð´Ð¾ ÑлеменÑа. Так, напÑимеÑ, в геомеÑÑиÑеÑÐºÐ¸Ñ Ð¿ÑиложениÑÑ Ð±ÑÐ²Ð°ÐµÑ Ð´Ð¾ÑÑаÑоÑно опÑеделиÑÑ Ð´Ð¸ÑÑанÑÐ¸Ñ Ð´Ð¾ опиÑанного пÑÑмоÑголÑника. ÐÐ»Ñ Ð²Ð½ÑÑÑеннего Ñзла деÑева ÑезÑлÑÑÐ°Ñ Ð½Ðµ должен пÑевÑÑаÑÑ Ð´Ð¸ÑÑанÑÐ¸Ñ Ð´Ð¾ лÑбого из его доÑеÑÐ½Ð¸Ñ Ñзлов. ÐÑли возвÑаÑÐ°ÐµÐ¼Ð°Ñ Ð´Ð¸ÑÑанÑÐ¸Ñ Ð½ÐµÑоÑнаÑ, ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° ÑÑÑановиÑÑ Ñлаг
*recheck. (ÐÑо необÑзаÑелÑно Ð´Ð»Ñ Ð²Ð½ÑÑÑÐµÐ½Ð½Ð¸Ñ Ñзлов деÑева; Ð´Ð»Ñ Ð½Ð¸Ñ ÑезÑлÑÑÐ°Ñ Ð²Ñегда ÑÑиÑаеÑÑÑ Ð½ÐµÑоÑнÑм.) Ð ÑÑом ÑлÑÑае иÑполниÑÐµÐ»Ñ Ð²ÑÑиÑÐ»Ð¸Ñ ÑоÑнÑÑ Ð´Ð¸ÑÑанÑиÑ, вÑбÑав коÑÑеж из кÑÑи, и пеÑеÑпоÑÑдоÑÐ¸Ñ ÐºÐ¾ÑÑежи пÑи Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ÑÑи.ÐÑли ÑÑнкÑÐ¸Ñ distance возвÑаÑаеÑ
*recheck = trueÐ´Ð»Ñ Ð»Ñбого Ñзла на ÑÑовне лиÑÑÑев, Ñипом ÑезÑлÑÑаÑа иÑÑ Ð¾Ð´Ð½Ð¾Ð³Ð¾ опеÑаÑоÑа ÑпоÑÑдоÑÐ¸Ð²Ð°Ð½Ð¸Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ бÑÑÑfloat8илиfloat4, и знаÑÐµÐ½Ð¸Ñ ÑезÑлÑÑаÑа ÑÑнкÑии distance Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ ÑÑÐ°Ð²Ð½Ð¸Ð¼Ñ Ñ ÑезÑлÑÑаÑами иÑÑ Ð¾Ð´Ð½Ð¾Ð³Ð¾ опеÑаÑоÑа ÑпоÑÑдоÑиваниÑ, Ñак как иÑполниÑÐµÐ»Ñ Ð±ÑÐ´ÐµÑ Ð²ÑполнÑÑÑ ÑоÑÑиÑовкÑ, иÑполÑзÑÑ Ð¸ ÑезÑлÑÑаÑÑ ÑÑнкÑии distance, и ÑÑоÑнÑннÑе ÑезÑлÑÑаÑÑ Ð¾Ð¿ÐµÑаÑоÑа ÑпоÑÑдоÑиваниÑ. РпÑоÑивном ÑлÑÑае знаÑениÑми ÑезÑлÑÑаÑа distance могÑÑ Ð±ÑÑÑ Ð»ÑбÑе конеÑнÑе знаÑениÑfloat8, пÑи ÑÑловии, ÑÑо оÑноÑиÑелÑнÑй поÑÑдок знаÑений ÑезÑлÑÑаÑа ÑооÑвеÑÑÑвÑÐµÑ Ð¿Ð¾ÑÑдкÑ, коÑоÑÑй даÑÑ Ð¾Ð¿ÐµÑаÑÐ¾Ñ ÑпоÑÑдоÑиваниÑ. (ÐнаÑÐµÐ½Ð¸Ñ Ð±ÐµÑконеÑноÑÑÑ Ð¸ минÑÑ Ð±ÐµÑконеÑноÑÑÑ Ð¿ÑименÑÑÑÑÑ Ð²Ð½ÑÑÑи Ð´Ð»Ñ Ð¾ÑобÑÑ ÑлÑÑаев, напÑимеÑ, пÑедÑÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ NULL, поÑÑÐ¾Ð¼Ñ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ Ñакие знаÑÐµÐ½Ð¸Ñ Ð¸Ð· ÑÑнкÑийdistanceне ÑекомендÑеÑÑÑ.)fetchÐÑеобÑазÑÐµÑ ÑжаÑое пÑедÑÑавление ÑлеменÑа даннÑÑ Ð² индекÑе в иÑÑ Ð¾Ð´Ð½Ñй Ñип даннÑÑ , Ð´Ð»Ñ ÑканиÑÐ¾Ð²Ð°Ð½Ð¸Ñ ÑолÑко индекÑа. ÐозвÑаÑаемÑе даннÑе Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ ÑоÑной, не пÑимеÑной копией изнаÑалÑно пÑоиндекÑиÑованного знаÑениÑ.
Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_fetch(internal) RETURNS internal AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
РкаÑеÑÑве аÑгÑменÑа ей пеÑедаÑÑÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° ÑÑÑÑкÑÑÑÑ
GISTENTRY. ÐÑи вÑзове ÐµÑ Ð¿Ð¾Ð»ÐµkeyÑодеÑÐ¶Ð¸Ñ Ð´Ð°Ð½Ð½Ñе лиÑÑа в ÑжаÑой ÑоÑме (не NULL). ÐозвÑаÑаемое знаÑение â еÑÑ Ð¾Ð´Ð½Ð° ÑÑÑÑкÑÑÑаGISTENTRY, в коÑоÑой полеkeyÑодеÑÐ¶Ð¸Ñ Ñе же даннÑе в иÑÑ Ð¾Ð´Ð½Ð¾Ð¹, ÑазвÑÑнÑÑой ÑоÑме. ÐÑли ÑÑнкÑиÑcompressклаÑÑа опеÑаÑоÑов не Ð´ÐµÐ»Ð°ÐµÑ Ñ Ð´Ð°Ð½Ð½Ñми лиÑÑÑев ниÑего, меÑодfetchÐ¼Ð¾Ð¶ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑиÑÑ Ð°ÑгÑÐ¼ÐµÐ½Ñ Ð±ÐµÐ· изменений. Ðибо, еÑли клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов не Ð¸Ð¼ÐµÐµÑ ÑÑнкÑииcompress, меÑодfetchÑоже Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¾Ð¿ÑÑен, Ñак как он в лÑбом ÑлÑÑае не должен ниÑего делаÑÑ.СооÑвеÑÑÑвÑÑÑий код в модÑле C должен ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_fetch); Datum my_fetch(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); input_data_type *in = DatumGetPointer(entry->key); fetched_data_type *fetched_data; GISTENTRY *retval; retval = palloc(sizeof(GISTENTRY)); fetched_data = palloc(sizeof(fetched_data_type)); /* * ÐÑеобÑазоваÑÑ ÑÑÑÑкÑÑÑÑ 'fetched_data' в Datum иÑÑ Ð¾Ð´Ð½Ð¾Ð³Ð¾ Ñипа даннÑÑ . */ /* ÐаполниÑÑ *retval из fetch_data. */ gistentryinit(*retval, PointerGetDatum(converted_datum), entry->rel, entry->page, entry->offset, FALSE); PG_RETURN_POINTER(retval); }ÐÑли меÑод ÑжаÑÐ¸Ñ ÑвлÑеÑÑÑ Ð½ÐµÑоÑнÑм Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñей ÑÑÐ¾Ð²Ð½Ñ Ð»Ð¸ÑÑÑев, Ñакой клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов не Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð´Ð´ÐµÑживаÑÑ ÑканиÑование ÑолÑко индекÑа и не должен опÑеделÑÑÑ ÑÑнкÑиÑ
fetch.optionsÐозволÑÐµÑ Ð¾Ð¿ÑеделиÑÑ Ð²Ð¸Ð´Ð¸Ð¼Ñе полÑзоваÑÐµÐ»Ñ Ð¿Ð°ÑамеÑÑÑ, ÑпÑавлÑÑÑие поведением клаÑÑа опеÑаÑоÑов.
Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_options(internal) RETURNS void AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
ÐÑой ÑÑнкÑии пеÑедаÑÑÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° ÑÑÑÑкÑÑÑÑ
local_relopts, в коÑоÑÑÑ Ð½Ñжно внеÑÑи Ð½Ð°Ð±Ð¾Ñ Ð¿Ð°ÑамеÑÑов, оÑноÑÑÑÐ¸Ñ ÑÑ Ðº клаÑÑÑ Ð¾Ð¿ÐµÑаÑоÑов. ÐбÑаÑаÑÑÑÑ Ðº ÑÑим паÑамеÑÑам из дÑÑÐ³Ð¸Ñ Ð¾Ð¿Ð¾ÑнÑÑ ÑÑнкÑий можно Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¼Ð°ÐºÑоÑовPG_HAS_OPCLASS_OPTIONS()иPG_GET_OPCLASS_OPTIONS().Ðиже показан пÑÐ¸Ð¼ÐµÑ ÑеализаÑии ÑÑнкÑии my_options() и иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð°ÑамеÑÑов из дÑÑÐ³Ð¸Ñ Ð¾Ð¿Ð¾ÑнÑÑ ÑÑнкÑий:
typedef enum MyEnumType { MY_ENUM_ON, MY_ENUM_OFF, MY_ENUM_AUTO } MyEnumType; typedef struct { int32 vl_len_; /* заголовок varlena (не менÑйÑе его напÑÑмÑÑ!) */ int int_param; /* ÑелоÑиÑленнÑй паÑамеÑÑ */ double real_param; /* паÑамеÑÑ Ñ Ð¿Ð»Ð°Ð²Ð°ÑÑей ÑоÑкой */ MyEnumType enum_param; /* паÑамеÑÑ-пеÑеÑиÑление */ int str_param; /* ÑÑÑоковÑй паÑамеÑÑ */ } MyOptionsStruct; /* СÑÑоковое пÑедÑÑавление знаÑений в пеÑеÑиÑлении */ static relopt_enum_elt_def myEnumValues[] = { {"on", MY_ENUM_ON}, {"off", MY_ENUM_OFF}, {"auto", MY_ENUM_AUTO}, {(const char *) NULL} /* завеÑÑаÑÑий ÑÐ»ÐµÐ¼ÐµÐ½Ñ ÑпиÑка */ }; static char *str_param_default = "default"; /* * ÐÑÐ¸Ð¼ÐµÑ Ð¿ÑовеÑоÑной ÑÑнкÑии: пÑовеÑÑеÑ, ÑÑо ÑÑÑока не длиннее 8 байÑ. */ static void validate_my_string_relopt(const char *value) { if (strlen(value) > 8) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("str_param must be at most 8 bytes"))); } /* * ÐÑÐ¸Ð¼ÐµÑ ÑÑнкÑии-заполниÑелÑ: пеÑÐµÐ²Ð¾Ð´Ð¸Ñ ÑÐ¸Ð¼Ð²Ð¾Ð»Ñ Ð² нижний ÑегиÑÑÑ. */ static Size fill_my_string_relopt(const char *value, void *ptr) { char *tmp = str_tolower(value, strlen(value), DEFAULT_COLLATION_OID); int len = strlen(tmp); if (ptr) strcpy(ptr, tmp); pfree(tmp); return len + 1; } PG_FUNCTION_INFO_V1(my_options); Datum my_options(PG_FUNCTION_ARGS) { local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0); init_local_reloptions(relopts, sizeof(MyOptionsStruct)); add_local_int_reloption(relopts, "int_param", "integer parameter", 100, 0, 1000000, offsetof(MyOptionsStruct, int_param)); add_local_real_reloption(relopts, "real_param", "real parameter", 1.0, 0.0, 1000000.0, offsetof(MyOptionsStruct, real_param)); add_local_enum_reloption(relopts, "enum_param", "enum parameter", myEnumValues, MY_ENUM_ON, "Valid values are: \"on\", \"off\" and \"auto\".", offsetof(MyOptionsStruct, enum_param)); add_local_string_reloption(relopts, "str_param", "string parameter", str_param_default, &validate_my_string_relopt, &fill_my_string_relopt, offsetof(MyOptionsStruct, str_param)); PG_RETURN_VOID(); } PG_FUNCTION_INFO_V1(my_compress); Datum my_compress(PG_FUNCTION_ARGS) { int int_param = 100; double real_param = 1.0; MyEnumType enum_param = MY_ENUM_ON; char *str_param = str_param_default; /* * ÐбÑÑно когда в клаÑÑе опеÑаÑоÑов опÑеделÑн меÑод 'options', полÑÑеннÑе ÑеÑез него * паÑамеÑÑÑ Ð²Ñегда пеÑедаÑÑÑÑ Ð¾Ð¿Ð¾ÑнÑм ÑÑнкÑиÑм. Ðднако, еÑли Ð²Ñ Ð´Ð¾Ð±Ð°Ð²Ð¸Ñе меÑод 'options' в * ÑÑÑеÑÑвÑÑÑий клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов, в Ñанее ÑозданнÑÑ Ð¸Ð½Ð´ÐµÐºÑÐ°Ñ Ð¿Ð°ÑамеÑÑов не бÑдеÑ, поÑÑÐ¾Ð¼Ñ * Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð° ÑледÑÑÑÐ°Ñ Ð¿ÑовеÑка. */ if (PG_HAS_OPCLASS_OPTIONS()) { MyOptionsStruct *options = (MyOptionsStruct *) PG_GET_OPCLASS_OPTIONS(); int_param = options->int_param; real_param = options->real_param; enum_param = options->enum_param; str_param = GET_STRING_RELOPTION(options, str_param); } /* пÑодолжение ÑеализаÑии опоÑной ÑÑнкÑии */ }Так как в GiST пÑедÑÑавление клÑÑа допÑÑÐºÐ°ÐµÑ Ð³Ð¸Ð±ÐºÐ¾ÑÑÑ, могÑÑ Ð±ÑÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ Ð¿Ð°ÑамеÑÑÑ Ð´Ð»Ñ Ð½Ð°ÑÑÑойки ÑÑого индекÑа. ÐапÑимеÑ, можно задаÑÑ Ð´Ð»Ð¸Ð½Ñ ÐºÐ»ÑÑа ÑигнаÑÑÑÑ. РкаÑеÑÑве пÑимеÑа ÑаÑÑмоÑÑиÑе ÑÑнкÑиÑ
gtsvector_options().sortsupportÐозвÑаÑÐ°ÐµÑ ÑÑнкÑиÑ-компаÑаÑÐ¾Ñ Ð´Ð»Ñ ÑоÑÑиÑовки даннÑÑ Ñ ÑÐ¾Ñ Ñанением локалÑноÑÑи. Ðна иÑполÑзÑеÑÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ð¼Ð¸
CREATE INDEXиREINDEX. ÐаÑеÑÑво Ñозданного индекÑа завиÑÐ¸Ñ Ð¾Ñ Ñого, наÑколÑко Ñ Ð¾ÑоÑо поÑÑдок ÑоÑÑиÑовки, опÑеделÑннÑй ÑÑнкÑией-компаÑаÑоÑом, ÑÐ¾Ñ ÑанÑÐµÑ Ð»Ð¾ÐºÐ°Ð»ÑноÑÑÑ Ð²Ð²Ð¾Ð´Ð¸Ð¼ÑÑ Ð´Ð°Ð½Ð½ÑÑ .ÐеÑод
sortsupportне ÑвлÑеÑÑÑ Ð¾Ð±ÑзаÑелÑнÑм. ÐÑли он не пÑедоÑÑавлÑеÑÑÑ,CREATE INDEXÑоздаÑÑ Ð¸Ð½Ð´ÐµÐºÑ, вÑÑавлÑÑ ÐºÐ°Ð¶Ð´Ñй коÑÑеж в деÑево Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑÑнкÑийpenaltyиpicksplit, но ÑÑÐ¾Ñ ÑпоÑоб гоÑаздо медленнее.Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_sortsupport(internal) RETURNS void AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
РаÑгÑменÑе пеÑедаÑÑÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° ÑÑÑÑкÑÑÑÑ
SortSupport. Ðак минимÑм, Ð´Ð°Ð½Ð½Ð°Ñ ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° заполниÑÑ Ð² ней полеcomparator. ÐомпаÑаÑоÑÑ Ð¿ÐµÑедаÑÑÑÑ ÑÑи аÑгÑменÑа: два ÑлеменÑа Datum Ð´Ð»Ñ ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ð¸ ÑказаÑÐµÐ»Ñ Ð½Ð° ÑÑÑÑкÑÑÑÑSortSupport. Рданном ÑлÑÑае в Datum пеÑедаÑÑÑÑ Ð¸Ð½Ð´ÐµÐºÑиÑованнÑе знаÑÐµÐ½Ð¸Ñ Ð² Ñом ÑоÑмаÑе, в коÑоÑом они Ñ ÑанÑÑÑÑ Ð² индекÑе; Ñо еÑÑÑ Ð² ÑоÑмаÑе, возвÑаÑаемом меÑодомcompress. ÐолнÑй API опÑеделÑн в Ñайлеsrc/include/utils/sortsupport.h.СооÑвеÑÑÑвÑÑÑий код в модÑле C должен ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_sortsupport); static int my_fastcmp(Datum x, Datum y, SortSupport ssup) { /* establish order between x and y by computing some sorting value z */ int z1 = ComputeSpatialCode(x); int z2 = ComputeSpatialCode(y); return z1 == z2 ? 0 : z1 > z2 ? 1 : -1; } Datum my_sortsupport(PG_FUNCTION_ARGS) { SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0); ssup->comparator = my_fastcmp; PG_RETURN_VOID(); }translate_cmptypeÐÐ»Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ знаÑениÑ
CompareTypeвозвÑаÑÐ°ÐµÑ Ð½Ð¾Ð¼ÐµÑ ÑÑÑаÑегии, коÑоÑÑй иÑполÑзÑеÑÑÑ ÑÑим клаÑÑом опеÑаÑоÑов Ð´Ð»Ñ ÑооÑвеÑÑÑвÑÑÑей ÑÑнкÑионалÑноÑÑи. ÐÑли Ñ ÐºÐ»Ð°ÑÑа опеÑаÑоÑов Ð½ÐµÑ Ð¿Ð¾Ð´Ñ Ð¾Ð´ÑÑей ÑÑÑаÑегии, ÑÑнкÑÐ¸Ñ Ð²Ð¾Ð·Ð²ÑаÑаеÑInvalidStrategy.ÐÑполÑзÑеÑÑÑ Ð´Ð»Ñ ÑемпоÑалÑнÑÑ Ð¾Ð³ÑаниÑений индекÑов (ÑÐ°ÐºÐ¸Ñ ÐºÐ°Ðº
PRIMARY KEYиUNIQUE). ÐÑли клаÑÑ Ð¾Ð¿ÐµÑаÑоÑов пÑедоÑÑавлÑÐµÑ ÑÑÑ ÑÑнкÑÐ¸Ñ Ð¸ она возвÑаÑÐ°ÐµÑ ÑезÑлÑÑаÑÑ Ð´Ð»ÑCOMPARE_EQ, ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ иÑполÑзоваÑÑ Ð´Ð»Ñ ÑаÑÑи или ÑаÑÑей огÑаниÑÐµÐ½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа, не оÑноÑÑÑÐ¸Ñ ÑÑ ÐºWITHOUT OVERLAPS.ÐÐ°Ð½Ð½Ð°Ñ Ð¾Ð¿Ð¾ÑÐ½Ð°Ñ ÑÑнкÑÐ¸Ñ ÑооÑвеÑÑÑвÑÐµÑ ÑÑнкÑии-обÑабоÑÑÐ¸ÐºÑ Ð¸Ð½Ð´ÐµÐºÑного меÑода доÑÑÑпа
amtranslatecmptype(Ñм. Раздел 61.2). ФÑнкÑиÑ-обÑабоÑÑикamtranslatecmptypeÐ´Ð»Ñ Ð¸Ð½Ð´ÐµÐºÑов GiST вÑзÑÐ²Ð°ÐµÑ Ð¾Ð¿Ð¾ÑнÑÑ ÑÑнкÑиÑtranslate_cmptypeÑооÑвеÑÑÑвÑÑÑего ÑемейÑÑва опеÑаÑоÑов, поÑколÑÐºÑ Ñам меÑод доÑÑÑпа Ð´Ð»Ñ Ð¸Ð½Ð´ÐµÐºÑов GiST не Ð¸Ð¼ÐµÐµÑ ÑикÑиÑованнÑÑ Ð½Ð¾Ð¼ÐµÑов ÑÑÑаÑегий.Ð SQL ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° обÑÑвлÑÑÑÑÑ Ñак:
CREATE OR REPLACE FUNCTION my_translate_cmptype(integer) RETURNS smallint AS 'MODULE_PATHNAME' LANGUAGE C STRICT;
Ð ÑегиÑÑÑаÑÐ¸Ñ ÑемейÑÑва опеÑаÑоÑов должна вÑглÑдеÑÑ ÑледÑÑÑим обÑазом:
ALTER OPERATOR FAMILY my_opfamily USING gist ADD FUNCTION 12 ("any", "any") my_translate_cmptype(int);СооÑвеÑÑÑвÑÑÑий код в модÑле C должен ÑеализовÑваÑÑÑÑ Ð¿Ð¾ ÑÐ°ÐºÐ¾Ð¼Ñ ÑаблонÑ:
PG_FUNCTION_INFO_V1(my_translate_cmptype); Datum my_translate_cmptype(PG_FUNCTION_ARGS) { CompareType cmptype = PG_GETARG_INT32(0); StrategyNumber ret = InvalidStrategy; switch (cmptype) { case COMPARE_EQ: ret = BTEqualStrategyNumber; } PG_RETURN_UINT16(ret); }Ð Postgres Pro доÑÑÑпна одна ÑÑнкÑÐ¸Ñ Ð¿ÑеобÑазованиÑ
gist_translate_cmptype_common, пÑедназнаÑÐµÐ½Ð½Ð°Ñ Ð´Ð»Ñ ÐºÐ»Ð°ÑÑов опеÑаÑоÑов, коÑоÑÑе иÑполÑзÑÑÑ ÐºÐ¾Ð½ÑÑанÑÑRT*StrategyNumber. РаÑÑиÑениеbtree_gistопÑеделÑÐµÑ ÐµÑÑ Ð¾Ð´Ð½Ñ ÑÑнкÑÐ¸Ñ Ð¿ÑеобÑазованиÑgist_translate_cmptype_btree, пÑедназнаÑеннÑÑ Ð´Ð»Ñ ÐºÐ»Ð°ÑÑов опеÑаÑоÑов, коÑоÑÑе иÑполÑзÑÑÑ ÐºÐ¾Ð½ÑÑанÑÑBT*StrategyNumber.
ÐÑе опоÑнÑе меÑÐ¾Ð´Ñ GiST обÑÑно вÑзÑваÑÑÑÑ Ð² кÑаÑковÑеменнÑÑ
конÑекÑÑаÑ
памÑÑи; Ñо еÑÑÑ, CurrentMemoryContext ÑбÑаÑÑваеÑÑÑ Ð¿Ð¾Ñле обÑабоÑки каждого коÑÑежа. Таким обÑазом можно не забоÑиÑÑÑÑ Ð¾Ð± оÑвобождении лÑбÑÑ
блоков памÑÑи, вÑделеннÑÑ
ÑÑнкÑией palloc. Ðднако в некоÑоÑÑÑ
ÑлÑÑаÑÑ
Ð´Ð»Ñ Ð¾Ð¿Ð¾Ñного меÑода полезно кеÑиÑоваÑÑ ÐºÐ°ÐºÐ¸Ðµ-либо даннÑе Ð¼ÐµÐ¶Ð´Ñ Ð²Ñзовами. ÐÐ»Ñ ÑÑого нÑжно ÑазмеÑÑиÑÑ Ð´Ð¾Ð»Ð³Ð¾Ð¶Ð¸Ð²ÑÑие даннÑе в конÑекÑÑе fcinfo->flinfo->fn_mcxt и ÑоÑ
ÑаниÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° ниÑ
в fcinfo->flinfo->fn_extra. Такие даннÑе ÑмогÑÑ Ð¿ÑоÑÑÑеÑÑвоваÑÑ Ð²ÑÑ Ð²ÑÐµÐ¼Ñ Ð¾Ð¿ÐµÑаÑии Ñ Ð¸Ð½Ð´ÐµÐºÑом (напÑимеÑ, одно ÑканиÑование индекÑа GiST, поÑÑÑоение индекÑа или добавление коÑÑежа в индекÑ). Ðе забÑдÑÑе вÑзваÑÑ pfree Ð´Ð»Ñ Ð¿ÑедÑдÑÑего знаÑениÑ, заменÑÑ Ð·Ð½Ð°Ñение в fn_extra, ÑÑÐ¾Ð±Ñ Ð½Ðµ допÑÑÑиÑÑ Ð½Ð°ÐºÐ¾Ð¿Ð»ÐµÐ½Ð¸Ñ ÑÑеÑек памÑÑи в Ñ
оде опеÑаÑии.
63.2.4. РеализаÑÐ¸Ñ #
63.2.4.1. СпоÑÐ¾Ð±Ñ Ð¿Ð¾ÑÑÑÐ¾ÐµÐ½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑов GiST #
СамÑй пÑоÑÑой ÑпоÑоб поÑÑÑоиÑÑ Ð¸Ð½Ð´ÐµÐºÑ GiST â пÑоÑÑо добавлÑÑÑ Ð²Ñе запиÑи Ð¾Ð´Ð½Ñ Ð·Ð° дÑÑгой. Ðо Ð´Ð»Ñ Ð±Ð¾Ð»ÑÑÐ¸Ñ Ð¸Ð½Ð´ÐµÐºÑов ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð½ÑÑÑ Ð¼Ð½Ð¾Ð³Ð¾ вÑемени, поÑколÑÐºÑ ÐµÑли индекÑнÑе коÑÑежи ÑазбÑоÑÐ°Ð½Ñ Ð¿Ð¾ вÑÐµÐ¼Ñ Ð¸Ð½Ð´ÐµÐºÑÑ Ð¸ он наÑÑолÑко велик, ÑÑо не помеÑаеÑÑÑ Ð² кеÑе, поÑÑебÑеÑÑÑ Ð²ÑполниÑÑ Ð¼Ð½Ð¾Ð¶ÐµÑÑво неÑпоÑÑдоÑеннÑÑ Ð¾Ð¿ÐµÑаÑий ввода-вÑвода. Postgres Pro поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ Ð´Ð²Ð° алÑÑеÑнаÑивнÑÑ Ð¼ÐµÑода наÑалÑного поÑÑÑÐ¾ÐµÐ½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа GiST: Ñ ÑоÑÑиÑовкой и Ñ Ð±ÑÑеÑизаÑией.
ÐоÑÑÑоение индекÑа Ñ ÑоÑÑиÑовкой возможно, ÑолÑко еÑли вÑе клаÑÑÑ Ð¾Ð¿ÐµÑаÑоÑов, иÑполÑзÑемÑе индекÑом, пÑедоÑÑавлÑÑÑ ÑÑнкÑÐ¸Ñ sortsupport, как опиÑано в ÐодÑаздел 63.2.3. Ð Ñаком ÑлÑÑае даннÑй меÑод иÑполÑзÑеÑÑÑ Ð¿Ð¾ ÑмолÑаниÑ, как опÑималÑнÑй.
ÐÑи поÑÑÑоении индекÑа Ñ Ð±ÑÑеÑизаÑией коÑÑежи не вÑÑавлÑÑÑÑÑ Ð² Ð¸Ð½Ð´ÐµÐºÑ Ð½ÐµÐ¼ÐµÐ´Ð»ÐµÐ½Ð½Ð¾. ÐÑо позволÑÐµÑ ÐºÐ°ÑдиналÑно ÑокÑаÑиÑÑ ÑиÑло опеÑаÑий пÑоизволÑного доÑÑÑпа, ÑÑебÑÑÑÐ¸Ñ ÑÑ Ð¿Ñи обÑабоÑке неÑпоÑÑдоÑеннÑÑ Ð½Ð°Ð±Ð¾Ñов даннÑÑ . ÐÐ»Ñ Ñ Ð¾ÑоÑо ÑпоÑÑдоÑеннÑÑ Ð½Ð°Ð±Ð¾Ñов вÑигÑÑÑ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑнÑм или вообÑе оÑÑÑÑÑÑвоваÑÑ, Ñак как вÑего неÑколÑко ÑÑÑÐ°Ð½Ð¸Ñ Ð±ÑдÑÑ Ð¿ÑинимаÑÑ Ð½Ð¾Ð²Ñе коÑÑежи в один Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð²Ñемени и ÑÑи ÑÑÑаниÑÑ Ð±ÑдÑÑ ÑмеÑаÑÑÑÑ Ð² кеÑе, даже еÑли веÑÑ Ð¸Ð½Ð´ÐµÐºÑ Ð¾ÑÐµÐ½Ñ Ð±Ð¾Ð»ÑÑой.
ÐÑи поÑÑÑоении индекÑа Ñ Ð±ÑÑеÑизаÑией пÑиÑ
одиÑÑÑ Ð³Ð¾Ñаздо ÑаÑе вÑзÑваÑÑ ÑÑнкÑÐ¸Ñ penalty по ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ñ Ð¾Ð±ÑÑнÑм поÑÑÑоением, на ÑÑо ÑÑ
одÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе ÑеÑÑÑÑÑ Ð¿ÑоÑеÑÑоÑа. ÐÑоме Ñого, бÑÑеÑам ÑÑебÑеÑÑÑ Ð²Ñеменное меÑÑо на диÑке, вплоÑÑ Ð´Ð¾ ÑазмеÑа ÑезÑлÑÑиÑÑÑÑего индекÑа. ÐÑÑеÑизаÑÐ¸Ñ Ñакже Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð²Ð»Ð¸ÑÑÑ Ð½Ð° каÑеÑÑво ÑезÑлÑÑиÑÑÑÑего индекÑа, как в положиÑелÑнÑÑ, Ñак и в оÑÑиÑаÑелÑнÑÑ ÑÑоÑонÑ. ÐÑо влиÑние завиÑÐ¸Ñ Ð¾Ñ ÑазлиÑнÑÑ
ÑакÑоÑов, напÑимеÑ, Ð¾Ñ ÑаÑпÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ð¾ÑÑÑпаÑÑиÑ
даннÑÑ
и Ð¾Ñ ÑеализаÑии клаÑÑа опеÑаÑоÑов.
ÐÑли ÑоÑÑиÑовка невозможна, по ÑмолÑÐ°Ð½Ð¸Ñ Ð¿Ñи поÑÑÑоении индекÑа GiST вклÑÑаеÑÑÑ Ð±ÑÑеÑизаÑиÑ, когда ÑÐ°Ð·Ð¼ÐµÑ Ð¸Ð½Ð´ÐµÐºÑа доÑÑÐ¸Ð³Ð°ÐµÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ effective_cache_size. ÐÑÑеÑизаÑÐ¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ пÑинÑдиÑелÑно вклÑÑиÑÑ Ð¸Ð»Ð¸ оÑклÑÑиÑÑ Ð²ÑÑÑнÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¿Ð°ÑамеÑÑа buffering ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ CREATE INDEX. Ðоведение по ÑмолÑÐ°Ð½Ð¸Ñ Ð´Ð¾ÑÑаÑоÑно ÑÑÑекÑивно в болÑÑинÑÑве ÑлÑÑаев, но еÑли вÑ
однÑе даннÑе ÑпоÑÑдоÑенÑ, вÑклÑÑив бÑÑеÑизаÑиÑ, можно полÑÑиÑÑ Ð½ÐµÐºÐ¾ÑоÑое ÑÑкоÑение.
63.2.5. ÐÑимеÑÑ #
РнаÑÑоÑÑее вÑÐµÐ¼Ñ ÑдÑо ÑиÑÑÐµÐ¼Ñ Postgres Pro обеÑпеÑÐ¸Ð²Ð°ÐµÑ Ð¿Ð¾Ð´Ð´ÐµÑÐ¶ÐºÑ ÑекÑÑового поиÑка (индекÑаÑÐ¸Ñ Ñипов tsvector и tsquery), а Ñакже ÑÑнкÑионалÑноÑÑÑ R-деÑева Ð´Ð»Ñ Ð½ÐµÐºÐ¾ÑоÑÑÑ
вÑÑÑоеннÑÑ
геомеÑÑиÑеÑкиÑ
Ñипов даннÑÑ
. ÐлаÑÑÑ Ð¾Ð¿ÐµÑаÑоÑов GiST ÑодеÑжаÑÑÑ Ñакже и в ÑледÑÑÑиÑ
дополниÑелÑнÑÑ
модÑлÑÑ
(contrib):
btree_gistФÑнкÑионалÑноÑÑÑ B-деÑева Ð´Ð»Ñ ÑазлиÑнÑÑ Ñипов даннÑÑ
cubeÐндекÑиÑование Ð´Ð»Ñ Ð¼Ð½Ð¾Ð³Ð¾Ð¼ÐµÑнÑÑ ÐºÑбов
hstoreÐодÑÐ»Ñ Ð´Ð»Ñ Ñ ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ (клÑÑ, знаÑение)
intarrayRD-деÑево Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð¼ÐµÑнÑÑ Ð¼Ð°ÑÑивов знаÑений int4
ltreeÐндекÑиÑование дÑевовиднÑÑ ÑÑÑÑкÑÑÑ
pg_trgmÐ¡Ñ Ð¾Ð¶ÐµÑÑÑ ÑекÑÑа на оÑнове ÑÑаÑиÑÑики ÑÑигÑамм
segÐндекÑиÑование «диапазонов ÑиÑел Ñ Ð¿Ð»Ð°Ð²Ð°ÑÑей ÑоÑкой»