Gwrthbatrymau PostgreSQL: YMUNIADAU a NEUau Niweidiol

Byddwch yn wyliadwrus o weithrediadau sy'n dod Γ’ byfferau...
Gan ddefnyddio ymholiad bach fel enghraifft, gadewch i ni edrych ar rai dulliau cyffredinol o optimeiddio ymholiadau yn PostgreSQL. Chi sydd i benderfynu a ydych chi'n eu defnyddio ai peidio, ond mae'n werth gwybod amdanynt.

Mewn rhai fersiynau dilynol o PG gall y sefyllfa newid wrth i'r amserlennydd ddod yn fwy craff, ond ar gyfer 9.4/9.6 mae'n edrych tua'r un peth, ag yn yr enghreifftiau yma.

Gadewch i ni dderbyn cais go iawn:

SELECT
  TRUE
FROM
  "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" d
INNER JOIN
  "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅" doc_ex
    USING("@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚")
INNER JOIN
  "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" t_doc ON
    t_doc."@Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = d."Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
WHERE
  (d."Π›ΠΈΡ†ΠΎ3" = 19091 or d."Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊ" = 19091) AND
  d."$Π§Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ" IS NULL AND
  d."Π£Π΄Π°Π»Π΅Π½" IS NOT TRUE AND
  doc_ex."БостояниС"[1] IS TRUE AND
  t_doc."Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = 'ΠŸΠ»Π°Π½Π Π°Π±ΠΎΡ‚'
LIMIT 1;

am enwau byrddau a chaeauGellir trin enwau β€œRwsia” caeau a thablau yn wahanol, ond mater o chwaeth yw hwn. Gan fod y yma yn Tensor nid oes unrhyw ddatblygwyr tramor, ac mae PostgreSQL yn caniatΓ‘u inni roi enwau hyd yn oed mewn hieroglyffau, os ydynt wedi'i amgΓ‘u mewn dyfyniadau, yna mae'n well gennym enwi gwrthrychau yn ddiamwys ac yn glir fel nad oes unrhyw anghysondebau.
Edrychwn ar y cynllun canlyniadol:
Gwrthbatrymau PostgreSQL: YMUNIADAU a NEUau Niweidiol
[edrychwch ar explain.tensor.ru]

144ms a bron i 53K byffer - hynny yw, mwy na 400MB o ddata! A byddwn yn ffodus os yw pob un ohonynt yn y storfa erbyn amser ein cais, fel arall bydd yn cymryd llawer mwy o amser wrth eu darllen o ddisg.

Yr algorithm sydd bwysicaf!

Er mwyn gwneud y gorau o unrhyw gais rywsut, rhaid i chi ddeall yn gyntaf beth ddylai ei wneud.
Gadewch i ni adael datblygiad strwythur y gronfa ddata ei hun y tu allan i gwmpas yr erthygl hon am y tro, a chytuno y gallwn yn gymharol β€œrhad” ailysgrifennu'r cais a/neu rolio i'r gwaelod rai o'r pethau sydd eu hangen arnom mynegeion.

Felly y cais:
β€” yn gwirio bodolaeth rhyw ddogfen o leiaf
- yn y cyflwr sydd ei angen arnom ac o fath arbennig
- os mai'r awdur neu'r perfformiwr yw'r gweithiwr sydd ei angen arnom

YMUNWCH + TERFYN 1

Yn aml iawn mae'n haws i ddatblygwr ysgrifennu ymholiad lle mae nifer fawr o dablau'n cael eu cysylltu i ddechrau, ac yna dim ond un cofnod sydd ar Γ΄l o'r set gyfan hon. Ond nid yw haws i'r datblygwr yn golygu mwy effeithlon ar gyfer y gronfa ddata.
Yn ein hachos ni dim ond 3 bwrdd oedd - a beth yw'r effaith ...

Yn gyntaf, gadewch i ni gael gwared ar y cysylltiad Γ’'r tabl "Math o Ddogfen", ac ar yr un pryd dywedwch wrth y gronfa ddata. mae ein cofnod teip yn unigryw (rydym yn gwybod hyn, ond nid oes gan y trefnydd syniad eto):

WITH T AS (
  SELECT
    "@Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
  FROM
    "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
  WHERE
    "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = 'ΠŸΠ»Π°Π½Π Π°Π±ΠΎΡ‚'
  LIMIT 1
)
...
WHERE
  d."Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = (TABLE T)
...

Oes, os yw'r tabl/CTE yn cynnwys un maes o un cofnod, yna yn PG gallwch hyd yn oed ysgrifennu fel hyn, yn lle

d."Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = (SELECT "@Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" FROM T LIMIT 1)

Gwerthusiad diog mewn ymholiadau PostgreSQL

DidfapOr vs UNDEB

Mewn rhai achosion, bydd Bitmap Heap Scan yn costio llawer i ni - er enghraifft, yn ein sefyllfa ni, pan fydd cryn dipyn o gofnodion yn bodloni'r cyflwr gofynnol. Rydym yn ei gael oherwydd NEU cyflwr wedi'i droi'n BitmapOr- gweithredu yn y cynllun.
Gadewch i ni ddychwelyd at y broblem wreiddiol - mae angen i ni ddod o hyd i gofnod cyfatebol unrhyw un o'r amodau - hynny yw, nid oes angen chwilio am holl gofnodion 59K o dan y ddau amod. Y mae ffordd i weithio allan un cyflwr, a ewch i'r ail yn unig pan na chafwyd dim yn y cyntaf. Bydd y dyluniad canlynol yn ein helpu ni:

(
  SELECT
    ...
  LIMIT 1
)
UNION ALL
(
  SELECT
    ...
  LIMIT 1
)
LIMIT 1

Mae TERFYN β€œAllanol” 1 yn sicrhau bod y chwiliad yn dod i ben pan ganfyddir y cofnod cyntaf. Ac os yw eisoes wedi'i ganfod yn y bloc cyntaf, ni fydd yr ail floc yn cael ei weithredu (heb ei ddienyddio erioed o ran).

β€œCuddio amodau anodd o dan CASE”

Mae yna foment hynod anghyfleus yn yr ymholiad gwreiddiol – gwirio’r statws yn erbyn y tabl cysylltiedig β€œDocumentExtension”. Waeth beth yw gwirionedd amodau eraill yn y mynegiant (er enghraifft, d. NID YW β€œDileu” yn WIR), mae'r cysylltiad hwn bob amser yn cael ei weithredu ac yn β€œcostio adnoddau”. Bydd mwy neu lai ohonynt yn cael eu gwario - yn dibynnu ar faint y tabl hwn.
Ond gallwch chi addasu'r ymholiad fel bod chwilio am gofnod cysylltiedig yn digwydd dim ond pan fo gwir angen:

SELECT
  ...
FROM
  "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" d
WHERE
  ... /*index cond*/ AND
  CASE
    WHEN "$Π§Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ" IS NULL AND "Π£Π΄Π°Π»Π΅Π½" IS NOT TRUE THEN (
      SELECT
        "БостояниС"[1] IS TRUE
      FROM
        "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅"
      WHERE
        "@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" = d."@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚"
    )
  END

Unwaith o'r tabl cysylltiedig i ni nid oes angen unrhyw un o'r meysydd ar gyfer y canlyniad, yna cawn gyfle i droi JOIN i amod ar subquery.
Gadewch i ni adael y meysydd wedi'u mynegeio β€œy tu allan i'r cromfachau CASE”, ychwanegu amodau syml o'r cofnod i'r bloc PRYD - a nawr dim ond wrth basio i YNA y gweithredir yr ymholiad β€œtrwm”.

Fy enw olaf yw "Cyfanswm"

Rydym yn casglu'r ymholiad canlyniadol gyda'r holl fecaneg a ddisgrifir uchod:

WITH T AS (
  SELECT
    "@Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
  FROM
    "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
  WHERE
    "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = 'ΠŸΠ»Π°Π½Π Π°Π±ΠΎΡ‚'
)
  (
    SELECT
      TRUE
    FROM
      "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" d
    WHERE
      ("Π›ΠΈΡ†ΠΎ3", "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°") = (19091, (TABLE T)) AND
      CASE
        WHEN "$Π§Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ" IS NULL AND "Π£Π΄Π°Π»Π΅Π½" IS NOT TRUE THEN (
          SELECT
            "БостояниС"[1] IS TRUE
          FROM
            "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅"
          WHERE
            "@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" = d."@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚"
        )
      END
    LIMIT 1
  )
UNION ALL
  (
    SELECT
      TRUE
    FROM
      "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" d
    WHERE
      ("Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°", "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊ") = ((TABLE T), 19091) AND
      CASE
        WHEN "$Π§Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ" IS NULL AND "Π£Π΄Π°Π»Π΅Π½" IS NOT TRUE THEN (
          SELECT
            "БостояниС"[1] IS TRUE
          FROM
            "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅"
          WHERE
            "@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" = d."@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚"
        )
      END
    LIMIT 1
  )
LIMIT 1;

Addasu [i] fynegeion

Sylwodd llygad hyfforddedig fod yr amodau mynegeio yn is-flociau UNION ychydig yn wahanol - mae hyn oherwydd bod gennym eisoes fynegeion addas ar y bwrdd. Ac os nad oeddent yn bodoli, byddai'n werth creu: Dogfen (Person3, Math o Ddogfen) ΠΈ Dogfen (Dogfen Math, Gweithiwr).
am drefn y caeau mewn amodau HTO safbwynt y cynlluniwr, wrth gwrs, gallwch chi ysgrifennu (A, B) = (constA, constB)Ac (B, A) = (constB, constA). Ond wrth recordio yn nhrefn y meysydd yn y mynegai, mae cais o'r fath yn symlach yn fwy cyfleus i ddadfygio yn ddiweddarach.
Beth sydd yn y cynllun?
Gwrthbatrymau PostgreSQL: YMUNIADAU a NEUau Niweidiol
[edrychwch ar explain.tensor.ru]

Yn anffodus, roeddem yn anlwcus ac ni ddaethpwyd o hyd i unrhyw beth yn y bloc UNION cyntaf, felly roedd yr ail un yn dal i gael ei ddienyddio. Ond er hynny - yn unig 0.037ms ac 11 byffer!
Rydym wedi cyflymu'r cais ac wedi lleihau pwmpio data yn y cof sawl mil o weithiau, gan ddefnyddio technegau gweddol syml - canlyniad da gydag ychydig o gopi-past. πŸ™‚

Ffynhonnell: hab.com

Ychwanegu sylw