Antipatterns PostgreSQL: a’ dol seachad air seataichean agus a’ taghadh gu SQL

Bho àm gu àm feumaidh leasaiche cuir seachad seata de pharamadairean no eadhon taghadh slàn ris an iarrtas "aig an t-slighe a-steach". Aig amannan thig thu tarsainn air fuasglaidhean gu math neònach don duilgheadas seo.
Antipatterns PostgreSQL: a’ dol seachad air seataichean agus a’ taghadh gu SQL
Rachamaid air ais agus faic dè nach dèan sinn, carson, agus ciamar as urrainn dhuinn a dhèanamh nas fheàrr.

Cuir a-steach luachan gu dìreach a-steach don bhuidheann iarrtas

Mar as trice bidh e a’ coimhead rudeigin mar seo:

query = "SELECT * FROM tbl WHERE id = " + value

... no mar seo:

query = "SELECT * FROM tbl WHERE id = :param".format(param=value)

Tha an dòigh seo air a ràdh, air a sgrìobhadh agus eadhon air a tharraing gu leòr:

Antipatterns PostgreSQL: a’ dol seachad air seataichean agus a’ taghadh gu SQL

Cha mhòr an-còmhnaidh a tha seo slighe dhìreach gu in-stealladh SQL agus eallach neo-riatanach air loidsig gnìomhachais, a tha air èigneachadh air an loidhne ceist agad a “glue”.

Chan urrainnear an dòigh-obrach seo a dhearbhadh gu ìre ach ma tha sin riatanach a 'cleachdadh sgaradh ann an dreachan PostgreSQL 10 agus gu h-ìosal gus plana nas èifeachdaiche fhaighinn. Anns na dreachan sin, tha an liosta de earrannan a chaidh a sganadh air a dhearbhadh gun a bhith a ’toirt aire do na paramadairean tar-chuir, a-mhàin air bunait a’ bhuidheann tagraidh.

$n-argamaid

Cleachd luchd-àite tha paramadairean math, leigidh e leat a chleachdadh RÁITEAS ULLACHADH, a’ lughdachadh an luchd an dà chuid air loidsig a’ ghnìomhachais (tha sreang na ceiste air a chruthachadh agus air a thar-chuir dìreach aon turas) agus air frithealaiche an stòr-dàta (chan eil feum air ath-phàsadh agus clàradh airson gach cùis ceiste).

Àireamh caochlaideach de argamaidean

Bidh trioblaidean a’ feitheamh rinn nuair a tha sinn airson àireamh neo-aithnichte de argamaidean a thoirt seachad:

... id IN ($1, $2, $3, ...) -- $1 : 2, $2 : 3, $3 : 5, ...

Ma dh’ fhàgas sinn an t-iarrtas san fhoirm seo, ged a bheir e dìon dhuinn bho stealladh a dh’fhaodadh a bhith ann, leanaidh e fhathast gu feum an t-iarrtas a chur còmhla/parsadh. airson gach roghainn a rèir àireamh nan argamaidean. Tha e nas fheàrr na bhith ga dhèanamh a h-uile turas, ach faodaidh tu a dhèanamh às aonais.

Tha e gu leòr airson a dhol seachad air dìreach aon paramadair anns a bheil riochdachadh sreath sreathach:

... id = ANY($1::integer[]) -- $1 : '{2,3,5,8,13}'

Is e an aon eadar-dhealachadh gu bheil feum air an argamaid atharrachadh gu soilleir chun t-seòrsa raon a tha thu ag iarraidh. Ach chan eil seo ag adhbhrachadh dhuilgheadasan, oir tha fios againn mu thràth ro-làimh càite a bheil sinn a 'dol.

A’ gluasad sampall (matrix)

Mar as trice is iad seo a h-uile seòrsa de roghainnean airson seataichean dàta a ghluasad airson a chuir a-steach don stòr-dàta “ann an aon iarrtas”:

INSERT INTO tbl(k, v) VALUES($1,$2),($3,$4),...

A bharrachd air na duilgheadasan a tha air am mìneachadh gu h-àrd le “ath-gluing” an t-iarrtas, faodaidh seo cuideachd ar leantainn gu as cuimhne agus tubaist air an fhrithealaiche. Tha an adhbhar sìmplidh - tha PG a’ gleidheadh ​​​​cuimhne a bharrachd airson argamaidean, agus tha an àireamh de chlàran san t-seata air a chuingealachadh a-mhàin le feumalachdan tagraidh loidsig gnìomhachais. Ann an cùisean sònraichte clionaigeach bha agam ri fhaicinn tha argamaidean “àireamh” nas motha na $9000 - na dèan mar seo.

Nach ath-sgrìobh an t-iarrtas a 'cleachdadh mar-thà sreathachadh "dà-ìre".:

INSERT INTO tbl
SELECT
  unnest[1]::text k
, unnest[2]::integer v
FROM (
  SELECT
    unnest($1::text[])::text[] -- $1 : '{"{a,1}","{b,2}","{c,3}","{d,4}"}'
) T;

Tha, a thaobh luachan “iom-fhillte” taobh a-staigh raon, feumaidh iad a bhith air an cuairteachadh le luachan.
Tha e soilleir gun urrainn dhut san dòigh seo “leudachadh” taghadh le àireamh neo-riaghailteach de raointean.

mì-riaraichte, neo-chinnteach,…

Bho àm gu àm tha roghainnean ann airson a dhol seachad an àite “sreath de arrays” grunn “sreathan de cholbhan” air an tug mi iomradh anns an artaigil mu dheireadh:

SELECT
  unnest($1::text[]) k
, unnest($2::integer[]) v;

Leis an dòigh seo, ma nì thu mearachd nuair a bhios tu a’ cruthachadh liostaichean de luachan airson diofar cholbhan, tha e gu math furasta fhaighinn toraidhean ris nach robh dùil, a tha cuideachd an urra ri dreach an fhrithealaiche:

-- $1 : '{a,b,c}', $2 : '{1,2}'
-- PostgreSQL 9.4
k | v
-----
a | 1
b | 2
c | 1
a | 2
b | 1
c | 2
-- PostgreSQL 11
k | v
-----
a | 1
b | 2
c |

JSON

Bho dhreach 9.3, tha gnìomhan làn-chuimseach air a bhith aig PostgreSQL airson a bhith ag obair leis an t-seòrsa json. Mar sin, ma tha am mìneachadh air paramadairean cuir a-steach a’ nochdadh sa bhrobhsair agad, faodaidh tu a chruthachadh an sin json object airson ceist SQL:

SELECT
  key k
, value v
FROM
  json_each($1::json); -- '{"a":1,"b":2,"c":3,"d":4}'

Airson dreachan roimhe, faodar an aon dòigh a chleachdadh airson gach (hstore), ach faodaidh “convolution” ceart le bhith a’ teicheadh ​​bho nithean toinnte ann an hstore duilgheadasan adhbhrachadh.

json_populate_recordset

Ma tha fios agad ro-làimh gun tèid an dàta bhon raon json “cuir a-steach” a chleachdadh gus cuid de bhòrd a lìonadh, faodaidh tu tòrr a shàbhaladh ann an raointean “dereferencing” agus an cur gu na seòrsaichean a tha a dhìth le bhith a ’cleachdadh an gnìomh json_populate_recordset:

SELECT
  *
FROM
  json_populate_recordset(
    NULL::pg_class
  , $1::json -- $1 : '[{"relname":"pg_class","oid":1262},{"relname":"pg_namespace","oid":2615}]'
  );

json_to_recordset

Agus bidh an gnìomh seo dìreach “leudachadh” an raon de nithean a chaidh seachad ann an taghadh, gun a bhith an urra ri cruth a ’chlàir:

SELECT
  *
FROM
  json_to_recordset($1::json) T(k text, v integer);
-- $1 : '[{"k":"a","v":1},{"k":"b","v":2}]'
k | v
-----
a | 1
b | 2

TEMPORAL TABLE

Ach ma tha an ìre de dhàta anns an sampall a chaidh a ghluasad gu math mòr, tha e duilich agus uaireannan do-dhèanta a thilgeil a-steach do aon paramadair sreathach, leis gu bheil feum air aon-ùine. riarachadh àireamh mhòr de chuimhne. Mar eisimpleir, feumaidh tu pasgan mòr de dhàta a chruinneachadh air tachartasan bho shiostam a-muigh airson ùine mhòr, agus an uairsin bidh thu airson a phròiseasadh aon-ùine air taobh an stòr-dàta.

Anns a 'chùis seo, is e am fuasgladh as fheàrr a chleachdadh bùird sealach:

CREATE TEMPORARY TABLE tbl(k text, v integer);
...
INSERT INTO tbl(k, v) VALUES($1, $2); -- повторить много-много раз
...
-- тут делаем что-то полезное со всей этой таблицей целиком

Tha an dòigh-obrach math airson gluasad bho àm gu àm de mheudan mòra dàta.
Bho thaobh a bhith a’ toirt cunntas air structar an dàta aige, tha clàr sealach eadar-dhealaichte bho fhear “cunbhalach” ann an aon dòigh a-mhàin. ann an clàr siostam pg_class, agus a-steach pg_type, pg_depend, pg_attribute, pg_attrdef, ... - chan eil dad idir.

Mar sin, ann an siostaman lìn le àireamh mhòr de cheanglaichean geàrr-ùine airson gach aon dhiubh, cruthaichidh clàr mar sin clàran siostam ùra gach turas, a thèid a dhubhadh às nuair a tha an ceangal ris an stòr-dàta dùinte. Mu dheireadh, tha cleachdadh neo-riaghlaichte de TEMP TABLE a’ leantainn gu “sèid” de chlàran ann am pg_catalog agus a’ slaodadh sìos mòran obrachaidhean a bhios gan cleachdadh.
Gu dearbh, faodar dèiligeadh ri seo le bhith a 'cleachdadh trannsa bho àm gu àm VACUUM LÀN a rèir clàran catalog an t-siostaim.

Caochlaidhean seisean

Gabhamaid ris gu bheil làimhseachadh an dàta bhon chùis roimhe gu math toinnte airson aon cheist SQL, ach tha thu airson a dhèanamh gu math tric. Is e sin, tha sinn airson giullachd mhodhan-obrach a chleachdadh ann an DO bloc, ach bidh cleachdadh gluasad dàta tro chlàran sealach ro dhaor.

Cha bhith e comasach dhuinn cuideachd $n-parameters a chleachdadh airson a dhol gu bloc gun urra. Cuidichidh caochladairean seisean agus an gnìomh sinn gus faighinn a-mach às an t-suidheachadh seo suidheachadh_làithreach.

Ro tionndadh 9.2 bha e riatanach ro-rèiteachadh ainm-àite sònraichte custom_variable_classes airson caochladairean seisean “do”. Air dreachan làithreach faodaidh tu rudeigin mar seo a sgrìobhadh:

SET my.val = '{1,2,3}';
DO $$
DECLARE
  id integer;
BEGIN
  FOR id IN (SELECT unnest(current_setting('my.val')::integer[])) LOOP
    RAISE NOTICE 'id : %', id;
  END LOOP;
END;
$$ LANGUAGE plpgsql;
-- NOTICE:  id : 1
-- NOTICE:  id : 2
-- NOTICE:  id : 3

Faodar fuasglaidhean eile a lorg ann an cànanan modhan-obrach eile le taic.

A bheil sibh eòlach air dòighean sam bith eile? Co-roinn anns na beachdan!

Source: www.habr.com

Cuir beachd ann