52.1. ÐпоÑнÑе ÑÑнкÑии меÑода извлеÑÐµÐ½Ð¸Ñ Ð²ÑбоÑки
ФÑнкÑиÑ-обÑабоÑÑик TSM возвÑаÑÐ°ÐµÑ ÑÑÑÑкÑÑÑÑ TsmRoutine (вÑделеннÑÑ Ð²Ñзовом palloc) Ñ ÑказаÑелÑми на опоÑнÑе ÑÑнкÑии, опиÑаннÑе ниже. ÐолÑÑинÑÑво ÑÑиÑ
ÑÑнкÑий обÑзаÑелÑнÑе, но некоÑоÑÑе â неÑ, и иÑ
ÑказаÑели могÑÑ Ð±ÑÑÑ ÑÐ°Ð²Ð½Ñ NULL.
void
SampleScanGetSampleSize (PlannerInfo *root,
RelOptInfo *baserel,
List *paramexprs,
BlockNumber *pages,
double *tuples); ÐÑа ÑÑнкÑÐ¸Ñ Ð²ÑзÑваеÑÑÑ Ð²Ð¾ вÑÐµÐ¼Ñ Ð¿Ð»Ð°Ð½Ð¸ÑованиÑ. Ðна должна ÑаÑÑÑиÑаÑÑ ÑиÑло ÑÑÑÐ°Ð½Ð¸Ñ Ð¾ÑноÑениÑ, коÑоÑÑе бÑдÑÑ Ð¿ÑоÑиÑÐ°Ð½Ñ Ð¿Ñи пÑоÑÑом ÑканиÑовании, и ÑиÑло коÑÑежей, вÑбиÑаемÑÑ
пÑи ÑканиÑовании. (ÐапÑимеÑ, ÑÑи ÑиÑла можно полÑÑиÑÑ, оÑенив пÑоÑÐµÐ½Ñ Ð²ÑбиÑаемÑÑ
даннÑÑ
, а заÑем Ñмножив baserel->pages и baserel->tuples на ÑÑо знаÑение и окÑÑглив ÑезÑлÑÑÐ°Ñ Ð´Ð¾ ÑелÑÑ
.) СпиÑок paramexprs ÑодеÑÐ¶Ð¸Ñ Ð²ÑÑажениÑ, пеÑеданнÑе в паÑамеÑÑаÑ
пÑÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ TABLESAMPLE. ÐÑли Ð´Ð»Ñ Ñелей оÑÐµÐ½Ð¸Ð²Ð°Ð½Ð¸Ñ Ð½ÑÐ¶Ð½Ñ Ð¸Ñ
знаÑениÑ, ÑекомендÑеÑÑÑ Ð²Ð¾ÑполÑзоваÑÑÑÑ estimate_expression_value(), ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð¿ÑÑаÑÑÑÑ ÑвеÑÑи ÑÑи вÑÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ðº конÑÑанÑам; но Ð´Ð°Ð½Ð½Ð°Ñ ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° вÑдаваÑÑ Ð¾ÑÐµÐ½ÐºÑ ÑазмеÑа, даже еÑли ÑÑо не ÑдаÑÑÑÑ, и не должна вÑдаваÑÑ Ð¾ÑибкÑ, даже еÑли ÑÑиÑÐ°ÐµÑ Ð¿ÐµÑеданнÑе знаÑÐµÐ½Ð¸Ñ Ð½ÐµÐ²ÐµÑнÑми (помниÑе, ÑÑо ÑÑо ÑолÑко пÑиблизиÑелÑнÑе оÑенки ÑиÑел, коÑоÑÑе бÑдÑÑ Ð¿Ð¾Ð»ÑÑÐµÐ½Ñ Ð²Ð¾ вÑÐµÐ¼Ñ Ð²ÑполнениÑ). ÐаÑамеÑÑÑ pages и tuples ÑвлÑÑÑÑÑ Ð²ÑÑ
однÑми.
void
InitSampleScan (SampleScanState *node,
int eflags); ÐÑполнÑÐµÑ Ð¸Ð½Ð¸ÑиализаÑÐ¸Ñ Ð¿ÐµÑед вÑполнением Ñзла плана SampleScan. ÐÑа ÑÑнкÑÐ¸Ñ Ð²ÑзÑваеÑÑÑ Ð¿Ñи запÑÑке иÑполниÑелÑ. Ðна должна вÑполниÑÑ Ð²Ñе подгоÑовиÑелÑнÑе дейÑÑвиÑ, необÑ
одимÑе Ð´Ð»Ñ Ð½Ð°Ñала обÑабоÑки. Узел SampleScanState Ñже бÑл Ñоздан, но его поле tsm_state ÑодеÑÐ¶Ð¸Ñ NULL. ФÑнкÑÐ¸Ñ InitSampleScan Ð¼Ð¾Ð¶ÐµÑ Ð²ÑделиÑÑ ÑеÑез palloc облаÑÑÑ Ð´Ð»Ñ Ð»ÑбÑÑ
внÑÑÑенниÑ
даннÑÑ
, нÑжнÑÑ
меÑÐ¾Ð´Ñ Ð¸Ð·Ð²Ð»ÐµÑÐµÐ½Ð¸Ñ Ð²ÑбоÑки, и ÑоÑ
ÑаниÑÑ ÑказаÑÐµÐ»Ñ Ð½Ð° Ð½ÐµÑ Ð² node->tsm_state. ÐнÑоÑмаÑÐ¸Ñ Ð¾ ÑканиÑÑемой ÑаблиÑе можно полÑÑиÑÑ ÑеÑез дÑÑгие Ð¿Ð¾Ð»Ñ Ñзла SampleScanState (но замеÑÑÑе, ÑÑо деÑкÑипÑÐ¾Ñ ÑканиÑÐ¾Ð²Ð°Ð½Ð¸Ñ node->ss.ss_currentScanDesc еÑÑ Ð½Ðµ наÑÑÑоен). ÐаÑамеÑÑ eflags ÑодеÑÐ¶Ð¸Ñ Ð±Ð¸ÑовÑе Ñлаги, опиÑÑваÑÑие Ñежим ÑабоÑÑ Ð¸ÑполниÑÐµÐ»Ñ Ð´Ð»Ñ ÑÑого Ñзла плана.
Ðогда (eflags & EXEC_FLAG_EXPLAIN_ONLY) не Ñавно нÑлÑ, ÑобÑÑвенно ÑканиÑование не бÑÐ´ÐµÑ Ð²ÑполнÑÑÑÑÑ, поÑÑÐ¾Ð¼Ñ ÑÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° ÑделаÑÑ ÑолÑко Ñо, ÑÑо необÑ
одимо Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ ÑоÑÑоÑÐ½Ð¸Ñ Ñзла, подÑ
одÑÑего Ð´Ð»Ñ EXPLAIN и EndSampleScan.
ÐÑÑ ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ опÑÑÑиÑÑ (пÑиÑвоиÑÑ ÑказаÑÐµÐ»Ñ NULL), Ñогда вÑÑ Ð¸Ð½Ð¸ÑиализаÑиÑ, необÑ
Ð¾Ð´Ð¸Ð¼Ð°Ñ Ð´Ð»Ñ Ð¼ÐµÑода извлеÑÐµÐ½Ð¸Ñ Ð²ÑбоÑки, должна имеÑÑ Ð¼ÐµÑÑо в BeginSampleScan.
void
BeginSampleScan (SampleScanState *node,
Datum *params,
int nparams,
uint32 seed); ÐаÑÐ¸Ð½Ð°ÐµÑ Ð²Ñполнение ÑканиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð²ÑбоÑки. ÐÑа ÑÑнкÑÐ¸Ñ Ð²ÑзÑваеÑÑÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно пеÑед пеÑвой попÑÑкой вÑбÑаÑÑ ÐºÐ¾ÑÑеж и Ð¼Ð¾Ð¶ÐµÑ Ð²ÑзÑваÑÑÑÑ Ð¿Ð¾Ð²ÑоÑно, еÑли поÑÑебÑеÑÑÑ Ð¿ÐµÑезапÑÑÑиÑÑ ÑканиÑование. ÐнÑоÑмаÑÐ¸Ñ Ð¾ ÑканиÑÑемой ÑаблиÑе можно полÑÑиÑÑ ÑеÑез Ð¿Ð¾Ð»Ñ Ñзла SampleScanState (но замеÑÑÑе, ÑÑо деÑкÑипÑÐ¾Ñ ÑканиÑÐ¾Ð²Ð°Ð½Ð¸Ñ node->ss.ss_currentScanDesc еÑÑ Ð½Ðµ наÑÑÑоен). ÐаÑÑив params, Ð´Ð»Ð¸Ð½Ñ nparams, ÑодеÑÐ¶Ð¸Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð¿Ð°ÑамеÑÑов, пеÑеданнÑÑ
в пÑедложении TABLESAMPLE. ÐÑ
колиÑеÑÑво и ÑÐ¸Ð¿Ñ Ð·Ð°Ð´Ð°ÑÑÑÑ Ð² ÑпиÑке parameterTypes меÑода вÑбоÑки, и они гаÑанÑиÑованно не ÑÐ°Ð²Ð½Ñ NULL. ÐаÑамеÑÑ seed ÑодеÑÐ¶Ð¸Ñ Ð·Ð½Ð°Ñение заÑÑавки, коÑоÑое ÑÑÐ¾Ñ Ð¼ÐµÑод должен ÑÑиÑÑваÑÑ Ð¿Ñи генеÑаÑии лÑбÑÑ
ÑлÑÑайнÑÑ
ÑиÑел; ÑÑо либо Ñ
еÑ, полÑÑеннÑй из знаÑÐµÐ½Ð¸Ñ REPEATABLE, еÑли оно бÑло пеÑедано, либо ÑезÑлÑÑÐ°Ñ random() в пÑоÑивном ÑлÑÑае.
ÐÑа ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ ÑкоÑÑекÑиÑоваÑÑ Ð¿Ð¾Ð»Ñ node->use_bulkread и node->use_pagemode. ÐÑли поле node->use_bulkread Ñавно true (ÑÑо знаÑение по ÑмолÑаниÑ), пÑи ÑканиÑовании бÑÐ´ÐµÑ Ð¸ÑполÑзоваÑÑÑÑ ÑÑÑаÑÐµÐ³Ð¸Ñ Ð´Ð¾ÑÑÑпа к бÑÑеÑÑ, оÑиенÑиÑÐ¾Ð²Ð°Ð½Ð½Ð°Ñ Ð½Ð° пеÑеÑабоÑÐºÑ Ð±ÑÑеÑов поÑле иÑполÑзованиÑ. ÐÐ¾Ð¶ÐµÑ Ð±ÑÑÑ ÑазÑмнÑм пÑиÑвоиÑÑ ÐµÐ¼Ñ false, еÑли пÑи ÑканиÑовании бÑÐ´ÐµÑ Ð¿ÑоÑмаÑÑиваÑÑÑÑ ÑолÑко неболÑÑой пÑоÑÐµÐ½Ñ ÑÑÑаниÑ. ÐÑли поле node->use_pagemode Ñавно true (ÑÑо знаÑение по ÑмолÑаниÑ), пÑи ÑканиÑовании пÑовеÑка видимоÑÑи бÑÐ´ÐµÑ Ð²ÑполнÑÑÑÑÑ Ð² один пÑоÑ
од Ð´Ð»Ñ Ð²ÑеÑ
коÑÑежей на каждой пÑоÑмаÑÑиваемой ÑÑÑаниÑе. ÐÐ¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ ÑмÑÑл пÑиÑвоиÑÑ ÐµÐ¼Ñ false, еÑли пÑи ÑканиÑовании вÑбиÑаеÑÑÑ ÑолÑко неболÑÑой пÑоÑÐµÐ½Ñ ÐºÐ¾ÑÑежей на ÑÑÑаниÑе. Ð ÑезÑлÑÑаÑе бÑÐ´ÐµÑ Ð²ÑполнÑÑÑÑÑ Ð¼ÐµÐ½ÑÑе пÑовеÑок видимоÑÑи коÑÑежей, Ñ
оÑÑ ÐºÐ°Ð¶Ð´Ð°Ñ Ð¿ÑовеÑка бÑÐ´ÐµÑ Ð´Ð¾Ñоже, Ñак как поÑÑебÑÐµÑ ÑаÑÑиÑеннÑÑ Ð±Ð»Ð¾ÐºÐ¸ÑовкÑ.
ÐÑли меÑод вÑбоÑки помеÑен как repeatable_across_scans, он должен бÑÑÑ ÑпоÑобен вÑбиÑаÑÑ Ð¿Ñи повÑоÑном ÑканиÑовании ÑÐ¾Ñ Ð¶Ðµ Ð½Ð°Ð±Ð¾Ñ ÐºÐ¾ÑÑежей, ÑÑо бÑл вÑбÑан в пеÑвÑй Ñаз, Ñо еÑÑÑ Ð½Ð¾Ð²Ñй вÑзов BeginSampleScan должен пÑиводиÑÑ Ðº вÑбоÑке ÑеÑ
же коÑÑежей, ÑÑо и пÑедÑдÑÑий (еÑли паÑамеÑÑÑ TABLESAMPLE и знаÑение заÑÑавки не менÑÑÑÑÑ).
BlockNumber NextSampleBlock (SampleScanState *node);
ÐозвÑаÑÐ°ÐµÑ Ð½Ð¾Ð¼ÐµÑ Ð±Ð»Ð¾ÐºÐ° ÑледÑÑÑей ÑканиÑÑемой ÑÑÑаниÑÑ Ð»Ð¸Ð±Ð¾ InvalidBlockNumber, еÑли ÑÑÑÐ°Ð½Ð¸Ñ Ð´Ð»Ñ ÑканиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð½Ðµ оÑÑалоÑÑ.
ÐÑÑ ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ опÑÑÑиÑÑ (пÑиÑвоиÑÑ ÐµÑ ÑказаÑÐµÐ»Ñ NULL), в ÑÑом ÑлÑÑае код ÑдÑа пÑоизведÑÑ Ð¿Ð¾ÑледоваÑелÑное ÑканиÑование вÑего оÑноÑениÑ. Такое ÑканиÑование Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑÐ¸Ð½Ñ ÑонизиÑованнÑм, Ñак ÑÑо меÑод вÑбоÑки не должен полагаÑÑ, ÑÑо ÑÑÑаниÑÑ Ð¾ÑноÑÐµÐ½Ð¸Ñ ÐºÐ°Ð¶Ð´Ñй Ñаз пÑоÑмаÑÑиваÑÑÑÑ Ð² одном и Ñом же поÑÑдке.
OffsetNumber
NextSampleTuple (SampleScanState *node,
BlockNumber blockno,
OffsetNumber maxoffset); ÐозвÑаÑÐ°ÐµÑ Ð½Ð¾Ð¼ÐµÑ ÑмеÑÐµÐ½Ð¸Ñ ÑледÑÑÑего коÑÑежа, вÑбиÑаемого Ñ Ñказанной ÑÑÑаниÑÑ, либо InvalidOffsetNumber, еÑли коÑÑежей Ð´Ð»Ñ Ð²ÑбоÑки не оÑÑалоÑÑ. Ð maxoffset задаÑÑÑÑ Ð¼Ð°ÐºÑималÑнÑй Ð½Ð¾Ð¼ÐµÑ ÑмеÑениÑ, допÑÑÑимÑй на ÑÑой ÑÑÑаниÑе.
ÐÑимеÑание
NextSampleTuple не говоÑÐ¸Ñ Ñвно, Ð´Ð»Ñ ÐºÐ°ÐºÐ¸Ñ
из номеÑов ÑмеÑений в диапазоне 1 .. maxoffset дейÑÑвиÑелÑно ÑодеÑжаÑÑÑ Ð°ÐºÑÑалÑнÑе коÑÑежи. ÐÑо обÑÑно не пÑоблема, Ñак как код ÑдÑа игноÑиÑÑÐµÑ Ð·Ð°Ð¿ÑоÑÑ Ð½Ð° вÑбоÑÐºÑ Ð½ÐµÑÑÑеÑÑвÑÑÑиÑ
или невидимÑÑ
коÑÑежей; ÑÑо не должно пÑиводиÑÑ Ðº оÑклонениÑм в вÑбоÑке. Ðднако пÑи необÑ
одимоÑÑи ÑÑнкÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑовеÑиÑÑ node->ss.ss_currentScanDesc->rs_vistuples[] и понÑÑÑ, какие коÑÑежи акÑÑалÑÐ½Ñ Ð¸ видимÑ. (ÐÐ»Ñ ÑÑого ÑÑебÑеÑÑÑ, ÑÑÐ¾Ð±Ñ Ð¿Ñизнак node->use_pagemode ÑавнÑлÑÑ true.)
ÐÑимеÑание
ФÑнкÑÐ¸Ñ NextSampleTuple не должна полагаÑÑ, ÑÑо в blockno бÑÐ´ÐµÑ Ð¿Ð¾Ð»ÑÑен ÑÐ¾Ñ Ð¶Ðµ Ð½Ð¾Ð¼ÐµÑ ÑÑÑаниÑÑ, ÑÑо бÑл вÑдан пÑи поÑледнем вÑзове NextSampleBlock. ÐÑÐ¾Ñ Ð½Ð¾Ð¼ÐµÑ Ð¾Ð¿ÑеделÑнно бÑл вÑдан пÑи каком-Ñо пÑедÑдÑÑем вÑзове NextSampleBlock, но код ÑдÑа Ð¼Ð¾Ð¶ÐµÑ Ð²ÑзÑваÑÑ NextSampleBlock пеÑед Ñем, как ÑобÑÑвенно ÑканиÑоваÑÑ ÑÑÑаниÑÑ, Ð´Ð»Ñ Ð¿Ð¾Ð´Ð´ÐµÑжки ÑпÑеждаÑÑего ÑÑениÑ. Ðднако можно ÑаÑÑÑиÑÑваÑÑ Ð½Ð° Ñо, ÑÑо как ÑолÑко наÑнÑÑÑÑ Ð²ÑбоÑка коÑÑежей Ñ Ð¾Ð´Ð½Ð¾Ð¹ данной ÑÑÑаниÑÑ, вÑе поÑледÑÑÑие вÑÐ·Ð¾Ð²Ñ NextSampleTuple бÑдÑÑ Ð¾Ð±ÑаÑаÑÑÑÑ Ðº ÑÑой ÑÑÑаниÑе, пока не бÑÐ´ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑено знаÑение InvalidOffsetNumber.
void EndSampleScan (SampleScanState *node);
ÐавеÑÑÐ°ÐµÑ ÑканиÑование и оÑÐ²Ð¾Ð±Ð¾Ð¶Ð´Ð°ÐµÑ ÑеÑÑÑÑÑ. ÐбÑÑно пÑи ÑÑом не нÑжно оÑвобождаÑÑ Ð¿Ð°Ð¼ÑÑÑ, вÑделеннÑÑ ÑеÑез palloc, но вÑе видимÑе извне ÑеÑÑÑÑÑ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð¾ÑиÑенÑ. ÐÑÑ ÑÑнкÑÐ¸Ñ ÑаÑе вÑего можно опÑÑÑиÑÑ (пÑиÑвоиÑÑ ÐµÑ ÑказаÑÐµÐ»Ñ NULL), еÑли ÑÐ°ÐºÐ¸Ñ ÑеÑÑÑÑов неÑ.