Megosztás a következőn keresztül:


Alküldetek az Azure Cosmos DB for NoSQL-ben

A KÖVETKEZŐRE VONATKOZIK: NoSQL

Az al lekérdezés egy másik lekérdezésbe ágyazott lekérdezés az Azure Cosmos DB for NoSQL-ben. Az al lekérdezéseket belső lekérdezésnek vagy belső SELECTlekérdezésnek is nevezik. Az al lekérdezést tartalmazó utasítást általában külső lekérdezésnek nevezzük.

Az albekérdezések típusai

Az albekérdezéseknek két fő típusa van:

  • Korrelált: A külső lekérdezésből származó értékekre hivatkozó részquery. A rendszer minden olyan sorhoz egyszer kiértékeli az al lekérdezést, amelyet a külső lekérdezés feldolgoz.
  • Nem korrelált: A külső lekérdezésétől független részquery. A külső lekérdezés használata nélkül önállóan is futtatható.

Feljegyzés

Az Azure Cosmos DB csak korrelált alhálózatokat támogat.

Az albekérdezések tovább besorolhatók a visszaadott sorok és oszlopok száma alapján. Három típus létezik:

  • Táblázat: Több sort és több oszlopot ad vissza.
  • Többértékű: Több sort és egyetlen oszlopot ad vissza.
  • Skaláris: Egyetlen sort és egyetlen oszlopot ad vissza.

Az Azure Cosmos DB for NoSQL lekérdezései mindig egyetlen oszlopot (egyszerű értéket vagy összetett elemet) adnak vissza. Ezért csak a többértékű és a skaláris al lekérdezések alkalmazhatók. Többértékű részqueryt csak a FROM záradékban használhat relációs kifejezésként. Skaláris alqueryt használhat skaláris kifejezésként a vagy WHERE záradékbanSELECT, vagy relációs kifejezésként a FROM záradékban.

Többértékű al lekérdezések

A többértékű al lekérdezések egy elemkészletet adnak vissza, és mindig a FROM záradékban vannak használva. Ezeket a következő célokra használják:

  • Az (önillesztési) kifejezések optimalizálása JOIN .
  • Költséges kifejezések kiértékelése és többszöri hivatkozás.

Önillesztésű kifejezések optimalizálása

A többértékű al lekérdezések úgy optimalizálhatják JOIN a kifejezéseket, hogy predikátumokat nyomnak az egyes select-many kifejezések után, nem pedig a WHERE záradék összes keresztbe illesztése után.

Fontolja meg a következő lekérdezést:

SELECT VALUE
    COUNT(1)
FROM
    products p
JOIN 
    t in p.tags
JOIN 
    q in p.onHandQuantities
JOIN 
    s in p.warehouseStock
WHERE 
    t.name IN ("winter", "fall") AND
    (q.quantity BETWEEN 0 AND 10) AND
    NOT s.backstock

Ebben a lekérdezésben az index megfelel minden olyan elemnek, amelynek címkéje name"tél" vagy "esés", legalább egy quantity nulla és tíz között, és legalább egy raktár, ahol a backstockfalse. Az JOIN itt szereplő kifejezés minden egyező elem összes elemének kereszt-szorzatát warehouseStocktagsonHandQuantitieshajtja végre, mielőtt bármilyen szűrőt alkalmaz.

A WHERE záradék ezután alkalmazza a szűrő predikátumát minden egyes <c, t, n, s> rekordra. Ha például egy egyező elem mind a három tömbben tíz elemet tartalmaz, az 1000-es értékre 1 x 10 x 10 x 10bővül. Az itt található al lekérdezések segíthetnek kiszűrni az összekapcsolt tömbelemeket, mielőtt csatlakoznának a következő kifejezéshez.

Ez a lekérdezés egyenértékű az előzővel, de al lekérdezéseket használ:

SELECT VALUE
    COUNT(1)
FROM
    products p
JOIN 
    (SELECT VALUE t FROM t IN p.tags WHERE t.name IN ("winter", "fall"))
JOIN 
    (SELECT VALUE q FROM q IN p.onHandQuantities WHERE q.quantity BETWEEN 0 AND 10)
JOIN 
    (SELECT VALUE s FROM s IN p.warehouseStock WHERE NOT s.backstock)

Tegyük fel, hogy a címketömbben csak egy elem felel meg a szűrőnek, és a mennyiségi és a készlettömbhöz is öt elem tartozik. A JOIN kifejezések ezután (25) elemre bontanak ki 1 x 1 x 5 x 5 , szemben az első lekérdezés 1000 elemével.

Kiértékelés egyszer és hivatkozás többször

Az al lekérdezések segíthetnek optimalizálni a lekérdezéseket olyan költséges kifejezésekkel, mint a felhasználó által definiált függvények (UDF-ek), az összetett sztringek vagy az aritmetikai kifejezések. A kifejezés kiértékeléséhez egy részkikérdezés és egy JOIN kifejezés is használható, de sokszor hivatkozhat rá.

Tegyük fel, hogy a következő UDF (getTotalWithTax) van definiálva.

function getTotalWithTax(subTotal){
  return subTotal * 1.25;
}

A következő lekérdezés többször futtatja az UDF-et getTotalWithTax :

SELECT VALUE {
    subtotal: p.price,
    total: udf.getTotalWithTax(p.price)
}
FROM
    products p
WHERE
    udf.getTotalWithTax(p.price) < 22.25

Íme egy egyenértékű lekérdezés, amely csak egyszer futtatja az UDF-et:

SELECT VALUE {
    subtotal: p.price,
    total: totalPrice
}
FROM
    products p
JOIN
    (SELECT VALUE udf.getTotalWithTax(p.price)) totalPrice
WHERE
    totalPrice < 22.25

Tipp.

Tartsa szem előtt a kifejezések termékközi viselkedését JOIN . Ha az UDF-kifejezés kiértékelhető undefined, győződjön meg arról, hogy a JOIN kifejezés mindig egyetlen sort hoz létre úgy, hogy egy objektumot ad vissza az al lekérdezésből, nem pedig közvetlenül az értéket.

Mimikai illesztés külső referenciaadatokkal

Előfordulhat, hogy gyakran olyan statikus adatokra kell hivatkoznia, amelyek ritkán változnak, például mértékegységek. Ideális, ha nem duplikálja a statikus adatokat a lekérdezés minden eleméhez. Ennek a duplikációnak a elkerülése a tárterületen takarítható meg, és az egyes elemek méretének csökkentése révén javíthatja az írási teljesítményt. Egy alquery használatával statikus referenciaadatok gyűjteményével utánozhatja a belső illesztésű szemantikát.

Vegyük például ezt a méréskészletet:

Név Szorzó Alapegység
ng Nanogram 1.00E-09 Gramm
µg Mikrogramm 1.00E-06 Gramm
mg Milligramm 1.00E-03 Gramm
g Gramm 1.00E+00 Gramm
kg Kilogramm 1.00E+03 Gramm
Mg Megagram 1.00E+06 Gramm
Gg Gigagram 1.00E+09 Gramm

Az alábbi lekérdezés az adatokkal való összekapcsolás után adja hozzá az egység nevét a kimenethez:

SELECT
    s.id,
    (s.weight.quantity * m.multiplier) AS calculatedWeight,
    m.unit AS unitOfWeight
FROM
    shipments s
JOIN m IN (
    SELECT VALUE [
        {unit: 'ng', name: 'nanogram', multiplier: 0.000000001, baseUnit: 'gram'},
        {unit: 'µg', name: 'microgram', multiplier: 0.000001, baseUnit: 'gram'},
        {unit: 'mg', name: 'milligram', multiplier: 0.001, baseUnit: 'gram'},
        {unit: 'g', name: 'gram', multiplier: 1, baseUnit: 'gram'},
        {unit: 'kg', name: 'kilogram', multiplier: 1000, baseUnit: 'gram'},
        {unit: 'Mg', name: 'megagram', multiplier: 1000000, baseUnit: 'gram'},
        {unit: 'Gg', name: 'gigagram', multiplier: 1000000000, baseUnit: 'gram'}
    ]
)
WHERE
    s.weight.units = m.unit

Skaláris alqueries

A skaláris subquery kifejezés egy olyan részkikérdezés, amely egyetlen értékre van kiértékelve. A skaláris részquery kifejezés értéke az alquery kivetülésének (SELECT záradékának) értéke. A skaláris részquery kifejezéseket számos helyen használhatja, ahol a skaláris kifejezés érvényes. Használhat például skaláris alqueryt a kifejezésekben és a SELECTWHERE záradékokban is.

A skaláris részquery használata nem mindig segít optimalizálni a lekérdezést. Ha például egy skaláris alqueryt argumentumként ad át egy rendszernek vagy felhasználó által definiált függvénynek, az nem jár előnyökkel az erőforrásegységek (RU) felhasználásának vagy késésének csökkentésében.

A skaláris al lekérdezések további besorolása:

  • Egyszerű kifejezés skaláris alqueries
  • Skaláris al lekérdezések összesítése

Egyszerű kifejezés skaláris alqueries

Az egyszerű kifejezéssel rendelkező skaláris részquery egy korrelált alquery, amely olyan SELECT záradékkal rendelkezik, amely nem tartalmaz összesítő kifejezéseket. Ezek az al lekérdezések nem biztosítanak optimalizálási előnyöket, mivel a fordító egy nagyobb egyszerű kifejezéssé alakítja őket. Nincs összefüggés a belső és a külső lekérdezés között.

Első példaként tekintse meg ezt a triviális lekérdezést.

SELECT
    1 AS a,
    2 AS b

Ezt a lekérdezést egy egyszerű kifejezéssel rendelkező skaláris alquery használatával újraírhatja.

SELECT
    (SELECT VALUE 1) AS a, 
    (SELECT VALUE 2) AS b

Mindkét lekérdezés ugyanazt a kimenetet hozza létre.

[
  {
    "a": 1,
    "b": 2
  }
]

Ez a következő példa lekérdezés összefűzi az egyedi azonosítót egy előtaggal egyszerű kifejezéssel rendelkező skaláris alqueryként.

SELECT 
    (SELECT VALUE Concat('ID-', p.id)) AS internalId
FROM
    products p

Ez a példa egy egyszerű kifejezéssel rendelkező skaláris részlekérdezés használatával csak az egyes elemek megfelelő mezőit adja vissza. A lekérdezés minden elemhez kimenetet ad ki, de csak akkor tartalmazza a kivetített mezőt, ha megfelel az al lekérdezés szűrőjének.

SELECT
    p.id,
    (SELECT p.name WHERE CONTAINS(p.name, "glove")).name
FROM
    products p
[
  {
    "id": "03230",
    "name": "Winter glove"
  },
  {
    "id": "03238"
  },
  {
    "id": "03229"
  }
]

Skaláris al lekérdezések összesítése

Az aggregált skaláris alquery egy olyan alquery, amelynek a vetületében vagy szűrőjében aggregátumfüggvény található, amely egyetlen értékre kiértékelhető.

Első példaként vegye figyelembe az alábbi mezőkkel rendelkező elemet.

{
  "name": "Snow coat",
  "inventory": [
    {
      "location": "Redmond, WA",
      "quantity": 50
    },
    {
      "location": "Seattle, WA",
      "quantity": 30
    },
    {
      "location": "Washington, DC",
      "quantity": 25
    }
  ]
}

Íme egy alquery, amely egyetlen aggregátumfüggvény-kifejezéssel rendelkezik a vetületében. Ez a lekérdezés minden elemhez megszámolja az összes címkét.

SELECT
    p.name,
    (SELECT VALUE COUNT(1) FROM i IN p.inventory) AS locationCount
FROM
    products p
[
  {
    "name": "Snow coat",
    "locationCount": 3
  }
]

Ugyanez az al lekérdezés egy szűrővel.

SELECT
    p.name,
    (SELECT VALUE COUNT(1) FROM i IN p.inventory WHERE ENDSWITH(i.location, "WA")) AS washingtonLocationCount
FROM
    products p
[
  {
    "name": "Snow coat",
    "washingtonLocationCount": 2
  }
]

Íme egy másik, több aggregátumfüggvény-kifejezéssel rendelkező alquery:

SELECT
    p.name,
    (SELECT
        COUNT(1) AS locationCount,
        SUM(i.quantity) AS totalQuantity
    FROM i IN p.inventory) AS inventoryData
FROM
    products p
[
  {
    "name": "Snow coat",
    "inventoryData": {
      "locationCount": 2,
      "totalQuantity": 75
    }
  }
]

Végül íme egy lekérdezés, amely a vetületben és a szűrőben is aggregátum-alqueryt használ:

SELECT
    p.name,
    (SELECT VALUE AVG(q.quantity) FROM q IN p.inventory WHERE q.quantity > 10) AS averageInventory
FROM
    products p
WHERE
    (SELECT VALUE COUNT(1) FROM i IN p.inventory WHERE i.quantity > 10) >= 1
[
  {
    "name": "Snow coat",
    "averageInventory": 35
  }
]

A lekérdezés írásának optimálisabb módja, ha csatlakozik az alqueryhez, és hivatkozik az alquery aliasra a SELECT és a WHERE záradékokban is. Ez a lekérdezés hatékonyabb, mert az al lekérdezést csak az illesztés utasításán belül kell végrehajtania, a vetítésben és a szűrőben nem.

SELECT
    p.name,
    inventoryData.inventoryAverage
FROM
    products p
JOIN
    (SELECT 
        COUNT(1) AS inventoryCount, 
        AVG(i.quantity) as inventoryAverage 
    FROM i IN p.inventory 
    WHERE i.quantity > 10) AS inventoryData
WHERE
    inventoryData.inventoryCount >= 1

EXISTS kifejezés

Az Azure Cosmos DB for NoSQL lekérdezési motorja támogatja EXISTS a kifejezéseket. Ez a kifejezés egy a NoSQL-hez készült Azure Cosmos DB-be beépített összesítő skaláris alquery. EXISTS egy subquery kifejezést vesz fel, és visszaadja true , ha az al lekérdezés bármilyen sort ad vissza. Ellenkező esetben a visszaadott falseérték.

Mivel a lekérdezési motor nem tesz különbséget a logikai kifejezések és más skaláris kifejezések között, EXISTS használhatja mindkettőt SELECT és WHERE záradékot is. Ez a viselkedés ellentétben áll a T-SQL-sel, ahol a logikai kifejezések csak szűrőkre korlátozódnak.

Ha az EXISTS al lekérdezés egyetlen értéket undefinedad vissza, EXISTS akkor a kiértékelés eredménye hamis lesz. Vegyük például az alábbi lekérdezést, amely semmit sem ad vissza.

SELECT VALUE
    undefined

Ha a EXISTS kifejezést és az előző lekérdezést használja alqueryként, a kifejezés visszaadja false.

SELECT
    EXISTS (SELECT VALUE undefined)
[
  {
    "$1": false
  }
]

Ha az előző részkikérdezés ÉRTÉK kulcsszója nincs megadva, az al lekérdezés egyetlen üres objektummal rendelkező tömbre lesz kiértékelve.

SELECT
    undefined
[
  {}
]

Ezen a ponton a EXISTS kifejezés kiértékeli, mivel true az objektum ({}) technikailag kilép.

SELECT 
    EXISTS (SELECT undefined) 
[
  {
    "$1": true
  }
]

Gyakori használati eset ARRAY_CONTAINS , ha egy elemet egy tömbben lévő elem megléte alapján szűr. Ebben az esetben ellenőrizzük, hogy a tags tömb tartalmaz-e "felsőruházat" nevű elemet.

SELECT
    p.name,
    p.tags
FROM
    products p
WHERE
    ARRAY_CONTAINS(p.tags, "outerwear")

Ugyanez a lekérdezés alternatív lehetőségként is használható EXISTS .

SELECT
    p.name,
    p.tags
FROM
    products p
WHERE
    EXISTS (SELECT VALUE t FROM t IN p.tags WHERE t = "outerwear")

Emellett csak azt tudja ellenőrizni, ARRAY_CONTAINS hogy egy érték megegyezik-e a tömb bármely eleméhez. Ha összetettebb szűrőkre van szüksége a tömbtulajdonságokon, használja JOIN inkább.

Tekintse meg ezt a példaelemet egy olyan készletben, amelyben több elem található, amelyek mindegyike egy tömböt accessories tartalmaz.

{
  "name": "Unobtani road bike",
  "accessories": [
    {
      "name": "Front/rear tire",
      "type": "tire",
      "quantityOnHand": 5
    },
    {
      "name": "9-speed chain",
      "type": "chains",
      "quantityOnHand": 25
    },
    {
      "name": "Clip-in pedals",
      "type": "pedals",
      "quantityOnHand": 15
    }
  ]
}

Most vegye figyelembe a következő lekérdezést, amely az type egyes elemek tömbjének tulajdonságai és quantityOnHand tulajdonságai alapján szűr.

SELECT
    p.name,
    a.name AS accessoryName
FROM
    products p
JOIN
    a IN p.accessories
WHERE
    a.type = "chains" AND
    a.quantityOnHand >= 10
[
  {
    "name": "Unobtani road bike",
    "accessoryName": "9-speed chain"
  }
]

A gyűjtemény minden egyes eleme esetében a rendszer a tömbelemekkel végez keresztterméket. Ez a JOIN művelet lehetővé teszi a tömb tulajdonságainak szűrését. A lekérdezés ru-felhasználása azonban jelentős. Ha például 1000 elem minden tömbben 100 elemet tartalmazott, akkor az 100 000-hez (vagyis 100 000- hez) bővül 1,000 x 100 .

A használat EXISTS segíthet elkerülni ezt a drága keresztterméket. Ebben a következő példában a lekérdezés az alkérés tömbelemeire EXISTS szűr. Ha egy tömbelem megfelel a szűrőnek, akkor kivetíti, és EXISTS igaz értékre értékeli.

SELECT VALUE
    p.name
FROM
    products p
WHERE
    EXISTS (SELECT VALUE 
        a 
    FROM 
        a IN p.accessories
    WHERE
        a.type = "chains" AND
        a.quantityOnHand >= 10)
[
  "Unobtani road bike"
]

A lekérdezések aliast EXISTS is használhatnak, és hivatkozhatnak az aliasra a kivetítésben:

SELECT
    p.name,
    EXISTS (SELECT VALUE
        a 
    FROM 
        a IN p.accessories
    WHERE
        a.type = "chains" AND
        a.quantityOnHand >= 10) AS chainAccessoryAvailable
FROM
    products p
[
  {
    "name": "Unobtani road bike",
    "chainAccessoryAvailable": true
  }
]

TÖMB kifejezés

A kifejezéssel ARRAY tömbként vetítheti ki a lekérdezés eredményeit. Ezt a kifejezést csak a SELECT lekérdezés záradékában használhatja.

Ezekben a példákban tegyük fel, hogy van egy tároló, amely legalább ezt az elemet tartalmazza.

{
  "name": "Radimer mountain bike",
  "tags": [
    {
      "name": "road"
    },
    {
      "name": "bike"
    },
    {
      "name": "competitive"
    }
  ]
}

Ebben az első példában a kifejezést a záradékban használja a SELECT rendszer.

SELECT
    p.name,
    ARRAY (SELECT VALUE t.name FROM t in p.tags) AS tagNames
FROM
    products p
[
  {
    "name": "Radimer mountain bike",
    "tagNames": [
      "road",
      "bike",
      "competitive"
    ]
  }
]

Más al lekérdezésekhez hasonlóan a ARRAY kifejezéssel rendelkező szűrők is lehetségesek.

SELECT
    p.name,
    ARRAY (SELECT VALUE t.name FROM t in p.tags) AS tagNames,
    ARRAY (SELECT VALUE t.name FROM t in p.tags WHERE CONTAINS(t.name, "bike")) AS bikeTagNames
FROM
    products p
[
  {
    "name": "Radimer mountain bike",
    "tagNames": [
      "road",
      "bike",
      "competitive"
    ],
    "bikeTagNames": [
      "bike"
    ]
  }
]

A tömbkifejezések a záradék után FROM is jöhetnek az al lekérdezésekben.

SELECT
    p.name,
    n.t.name AS nonBikeTagName
FROM
    products p
JOIN
    n IN (SELECT VALUE ARRAY(SELECT t FROM t in p.tags WHERE t.name NOT LIKE "%bike%"))
[
  {
    "name": "Radimer mountain bike",
    "nonBikeTagName": "road"
  },
  {
    "name": "Radimer mountain bike",
    "nonBikeTagName": "competitive"
  }
]