PostgreSQL యాంటీప్యాటర్న్‌లు: "ఒక్కటి మాత్రమే ఉండాలి!"

SQLలో, మీరు "ఏమి సాధించాలనుకుంటున్నారు" అని వివరిస్తారు, అది "ఎలా" అని కాదు. అందువల్ల, SQL ప్రశ్నలను "విన్నట్లుగానే వ్రాయబడినది" అనే శైలిలో అభివృద్ధి చేయడంలో సమస్య దాని గౌరవ స్థానంలో ఉంటుంది. SQLలో పరిస్థితులను లెక్కించే లక్షణాలు.

ఈ రోజు, చాలా సరళమైన ఉదాహరణలను ఉపయోగించి, ఉపయోగం సందర్భంలో ఇది ఏమి దారితీస్తుందో చూద్దాం GROUP/DISTINCT и LIMIT వారితో.

ఇప్పుడు, మీరు అభ్యర్థనలో వ్రాసినట్లయితే "మొదట ఈ సంకేతాలను కనెక్ట్ చేయండి, ఆపై అన్ని నకిలీలను విసిరేయండి, ఒకటి మాత్రమే మిగిలి ఉండాలి ప్రతి కీకి కాపీ" - కనెక్షన్ అస్సలు అవసరం లేకపోయినా, ఇది సరిగ్గా ఎలా పని చేస్తుంది.

మరియు కొన్నిసార్లు మీరు అదృష్టవంతులు మరియు ఇది "కేవలం పని చేస్తుంది", కొన్నిసార్లు ఇది పనితీరుపై అసహ్యకరమైన ప్రభావాన్ని కలిగి ఉంటుంది మరియు కొన్నిసార్లు ఇది డెవలపర్ దృక్కోణం నుండి పూర్తిగా ఊహించని ప్రభావాలను ఇస్తుంది.

PostgreSQL యాంటీప్యాటర్న్‌లు: "ఒక్కటి మాత్రమే ఉండాలి!"
బాగా, బహుశా అంత అద్భుతమైనది కాకపోవచ్చు, కానీ ...

“స్వీట్ కపుల్”: జాయిన్ + డిస్టింక్

SELECT DISTINCT
  X.*
FROM
  X
JOIN
  Y
    ON Y.fk = X.pk
WHERE
  Y.bool_condition;

వారు ఏమి కోరుకుంటున్నారో స్పష్టంగా ఉంటుంది పూర్తి చేసిన స్థితికి సంబంధించిన రికార్డులు Yలో ఉన్న X రికార్డ్‌లను ఎంచుకోండి. ద్వారా అభ్యర్థన రాశారు JOIN — కొన్ని pk విలువలను అనేక సార్లు పొందారు (Y లో సరిగ్గా ఎన్ని సరైన ఎంట్రీలు కనిపించాయి). ఎలా తొలగించాలి? ఖచ్చితంగా DISTINCT!

ప్రతి ఎక్స్-రికార్డ్‌కు అనేక వందల సంబంధిత Y-రికార్డులు ఉన్నప్పుడు, ఆపై నకిలీలు వీరోచితంగా తొలగించబడినప్పుడు ఇది ప్రత్యేకంగా “సంతృప్తికరమైనది”...

PostgreSQL యాంటీప్యాటర్న్‌లు: "ఒక్కటి మాత్రమే ఉండాలి!"

ఎలా పరిష్కరించాలి? ప్రారంభించడానికి, సమస్యను సవరించవచ్చని గ్రహించండి "రికార్డులు Xని ఎంచుకోండి, దీని కోసం Y లో కనీసం ఒకదానిని నెరవేర్చిన షరతుతో అనుబంధించండి" - అన్ని తరువాత, మాకు Y- రికార్డ్ నుండి ఏమీ అవసరం లేదు.

నెస్టెడ్ EXISTS

SELECT
  *
FROM
  X
WHERE
  EXISTS(
    SELECT
      NULL
    FROM
      Y
    WHERE
      fk = X.pk AND
      bool_condition
    LIMIT 1
  );

PostgreSQL యొక్క కొన్ని సంస్కరణలు EXISTSలో వచ్చే మొదటి ఎంట్రీని కనుగొనడానికి సరిపోతాయని అర్థం చేసుకుంటాయి, పాతవి గుర్తించబడవు. అందువల్ల నేను ఎల్లప్పుడూ సూచించడానికి ఇష్టపడతాను LIMIT 1 లోపల EXISTS.

లేటరల్ జాయిన్

SELECT
  X.*
FROM
  X
, LATERAL (
    SELECT
      Y.*
    FROM
      Y
    WHERE
      fk = X.pk AND
      bool_condition
    LIMIT 1
  ) Y
WHERE
  Y IS DISTINCT FROM NULL;

అదే ఐచ్ఛికం అవసరమైతే, కనుగొనబడిన అనుబంధిత Y-రికార్డ్ నుండి కొంత డేటాను వెంటనే తిరిగి ఇవ్వడానికి అనుమతిస్తుంది. ఇదే విధమైన ఎంపిక వ్యాసంలో చర్చించబడింది "PostgreSQL యాంటీప్యాటర్న్‌లు: ఒక అరుదైన రికార్డ్ చేరడం మధ్యలో చేరుతుంది".

“ఎందుకు ఎక్కువ చెల్లించాలి”: DISTINCT [ON] + LIMIT 1

అటువంటి ప్రశ్న పరివర్తనల యొక్క అదనపు ప్రయోజనం ఏమిటంటే, కింది సందర్భంలో వలె వాటిలో ఒకటి లేదా కొన్ని మాత్రమే అవసరమైతే రికార్డ్‌ల కోసం శోధనను సులభంగా పరిమితం చేయగల సామర్థ్యం:

SELECT DISTINCT ON(X.pk)
  *
FROM
  X
JOIN
  Y
    ON Y.fk = X.pk
LIMIT 1;

ఇప్పుడు మేము అభ్యర్థనను చదివాము మరియు DBMS ఏమి చేయాలని ప్రతిపాదించబడిందో అర్థం చేసుకోవడానికి ప్రయత్నిస్తాము:

  • సంకేతాలను కలుపుతోంది
  • X.pk ద్వారా ప్రత్యేకమైనది
  • మిగిలిన ఎంట్రీల నుండి, ఒకదాన్ని ఎంచుకోండి

కాబట్టి మీరు ఏమి పొందారు? "ఒక్క ప్రవేశం" విశిష్టమైన వాటి నుండి - మరియు మనం ప్రత్యేకమైన వాటిలో దీన్ని తీసుకుంటే, ఫలితం ఏదో విధంగా మారుతుందా?

SELECT
  *
FROM
  (
    SELECT
      *
    FROM
      X
    -- сюда можно подсунуть подходящих условий
    LIMIT 1 -- +1 Limit
  ) X
JOIN
  Y
    ON Y.fk = X.pk
LIMIT 1;

మరియు సరిగ్గా అదే అంశం GROUP BY + LIMIT 1.

“నేను అడగాలి”: అవ్యక్త GROUP + LIMIT

ఇలాంటి విషయాలు వేర్వేరుగా జరుగుతాయి శూన్యత లేని తనిఖీలు అభ్యర్థన పురోగమిస్తున్నప్పుడు సంకేతాలు లేదా CTEలు:

...
CASE
  WHEN (
    SELECT
      count(*)
    FROM
      X
    LIMIT 1
  ) = 0 THEN ...

మొత్తం విధులు (count/min/max/sum/...) స్పష్టమైన సూచనలు లేకుండా కూడా మొత్తం సెట్‌లో విజయవంతంగా అమలు చేయబడతాయి GROUP BY. తో మాత్రమే LIMIT వారు చాలా స్నేహపూర్వకంగా లేరు.

డెవలపర్ ఆలోచించవచ్చు "అక్కడ రికార్డులు ఉంటే, నాకు LIMIT కంటే ఎక్కువ అవసరం లేదు". కానీ అలా చేయవద్దు! ఎందుకంటే బేస్ కోసం ఇది:

  • వారికి ఏమి కావాలో లెక్కించండి అన్ని రికార్డుల ప్రకారం
  • వారు అడిగినన్ని లైన్లు ఇవ్వండి

లక్ష్య పరిస్థితులపై ఆధారపడి, కింది ప్రత్యామ్నాయాలలో ఒకదాన్ని చేయడం సముచితం:

  • (count + LIMIT 1) = 0 NOT EXISTS(LIMIT 1)
  • (count + LIMIT 1) > 0 EXISTS(LIMIT 1)
  • count >= N (SELECT count(*) FROM (... LIMIT N))

"గ్రాముల బరువు ఎంత": DISTINCT + LIMIT

SELECT DISTINCT
  pk
FROM
  X
LIMIT $1

అభ్యర్థన అమలు చేయడం ఆపివేస్తుందని అమాయక డెవలపర్ హృదయపూర్వకంగా విశ్వసించవచ్చు. మేము కనిపించే మొదటి విభిన్న విలువలలో $1ని కనుగొన్న వెంటనే.

భవిష్యత్తులో ఇది కొత్త నోడ్‌కు ధన్యవాదాలు మరియు పని చేస్తుంది ఇండెక్స్ స్కిప్ స్కాన్, దీని అమలు ప్రస్తుతం పని చేస్తోంది, కానీ ఇంకా లేదు.

ప్రస్తుతానికి ముందుగా అన్ని రికార్డులు తిరిగి పొందబడతాయి, ప్రత్యేకమైనవి మరియు వారి నుండి మాత్రమే అభ్యర్థించిన మొత్తం తిరిగి ఇవ్వబడుతుంది. మనం అలాంటిదే కోరుకుంటే అది చాలా విచారకరం $ 1 = 4, మరియు పట్టికలో వందల వేల రికార్డులు ఉన్నాయి...

వ్యర్థంగా విచారంగా ఉండకుండా ఉండటానికి, పునరావృత ప్రశ్నను ఉపయోగిస్తాము PostgreSQL వికీ నుండి "DISTINCT is for the పేద":

PostgreSQL యాంటీప్యాటర్న్‌లు: "ఒక్కటి మాత్రమే ఉండాలి!"

మూలం: www.habr.com

ఒక వ్యాఖ్యను జోడించండి