Albekérdezések 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 alkérdezéseket belső lekérdezésnek vagy belső SELECT
leké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ó al lekérdezés. Az alkérelmek kiértékelése egyszer történik minden olyan sornál, amelyet a külső lekérdezés feldolgoz.
- Nem korrelált: A külső lekérdezéstől független alkérdezés. Önállóan is futtatható anélkül, hogy a külső lekérdezésre támaszkodna.
Megjegyzés
Az Azure Cosmos DB csak a korrelált albekérdezéseket támogatja.
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 adnak vissza (egy egyszerű értéket vagy egy összetett elemet). Ezért csak a többértékű és a skaláris al lekérdezések alkalmazhatók. A többértékű alkérdezéseket csak a FROM
záradékban használhatja relációs kifejezésként. A skaláris alkérdezéseket használhatja 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ű albekérdezések
A többértékű albekérdezések egy elemkészletet adnak vissza, és mindig a FROM
záradékon belül használják. Ezeket a következő célokra használják:
- Kifejezések optimalizálása
JOIN
(önillesztés). - Költséges kifejezések egyszer történő kiértékelése és többszöri hivatkozás.
Önillesztésű kifejezések optimalizálása
A többértékű albekérdezések úgy optimalizálhatják JOIN
a kifejezéseket, hogy predikátumokat nyomnak le minden select-many kifejezés után, nem pedig a WHERE
záradék összes keresztcsatlakozása után.
Tekintse 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, amely "téli" vagy "őszi" címkével rendelkezikname
, legalább egy quantity
nullátóltízig, és legalább egy raktárhoz, ahol a backstock
.false
Az JOIN
itt található kifejezés az egyes egyező elemekhez tartozó , és onHandQuantities
warehouseStock
tömbök összes elemének kereszttermékéttags
hajtja végre a szűrő alkalmazása előtt.
A WHERE
záradék ezután alkalmazza a szűrő predikátumot minden <c, t, n, s>
egyes rekordra. Ha például egy egyező elemet mind a három tömbben tíz elem tartalmaz, az 1000-ra bővül 1 x 10 x 10 x 10
. Az itt található albekérdezések segíthetnek a csatlakoztatott tömbelemek szűrésében, mielőtt csatlakozna 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 öt elem van mind a tápanyagokhoz, mind a kiszolgálótömbökhöz. A JOIN
kifejezések ezután (25) elemre bontanak, 1 x 1 x 5 x 5
szemben az első lekérdezés 1000 elemével.
Kiértékelés egyszer és hivatkozás sokszor
Az alkéré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 egyszer kiértékelhető egy kifejezéssel JOIN
együtt, de sokszor hivatkozhat rá.
Tegyük fel, hogy a következő UDF -t (getTotalWithTax
) definiálta.
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ő a értékre undefined
, győződjön meg arról, hogy a JOIN
kifejezés mindig egyetlen sort állít elő ú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. A duplikációk elkerülése a tárterületen takarítható meg, és az egyes elemek méretének kisebbre adásával javíthatja az írási teljesítményt. Az albekérdezésekkel statikus referenciaadatok gyűjteményével utánozhatja a belső illesztésű szemantikát.
Vegyük például a következő méréseket:
Név | Szorzó | Alapegység | |
---|---|---|---|
ng |
Nanogramm | 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 |
A következő 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 albekérdezések
A skaláris subquery kifejezés egy olyan részkikérdezés, amely egyetlen értékre van kiértékelve. A skaláris subquery kifejezés értéke az alquery vetületének (SELECT
záradékának) értéke. Skaláris subquery kifejezést számos olyan helyen használhat, ahol a skaláris kifejezés érvényes. Használhat például skaláris alkérdezéseket a és WHERE
a SELECT
záradékok bármely kifejezésében.
A skaláris alkérdezés használata nem mindig segít a lekérdezés optimalizálásában. 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) használatának vagy késésének csökkentésében.
A skaláris albekérdezések további besorolása:
- Egyszerű kifejezés skaláris alkérdezések
- Skaláris al lekérdezések összesítése
Egyszerű kifejezés skaláris alkérdezések
Az egyszerű kifejezések skaláris alqueryje 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ó egyetlen nagyobb egyszerű kifejezéssé alakítja őket. A belső és a külső lekérdezések között nincs korreláció.
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 átírhatja egy egyszerű kifejezéssel rendelkező skaláris alkérdezés használatával.
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éldában szereplő lekérdezés összefűzi az egyedi azonosítót egy előtaggal egyszerű kifejezés skaláris alkérdezésként.
SELECT
(SELECT VALUE Concat('ID-', p.id)) AS internalId
FROM
products p
Ez a példa egy egyszerű kifejezéssel rendelkező skaláris allekérdezés használatával csak az egyes elemek megfelelő mezőit adja vissza. A lekérdezés minden egyes 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átum skaláris alkikérdezések olyan al lekérdezések, amelyek a vetületében vagy szűrőjében egy összesítő függvényt is tartalmazó függvényt ad vissza, 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 al lekérdezés egyetlen aggregátumfüggvény-kifejezéssel a vetületében. Ez a lekérdezés az egyes elemekhez tartozó összes címkét megszámolja.
SELECT
p.name,
(SELECT VALUE COUNT(1) FROM i IN p.inventory) AS locationCount
FROM
products p
[
{
"name": "Snow coat",
"locationCount": 3
}
]
Itt ugyanaz az alké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ő al lekérdezés:
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 leképezésben és a szűrőben is aggregátumalkotó lekérdezéssel rendelkezik:
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 al lekérdezéshez, és hivatkozik a subquery aliasra a SELECT és a WHERE záradékban is. Ez a lekérdezés hatékonyabb, mert az al lekérdezést csak a join utasításon belül kell végrehajtania, a leképezé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 al lekérdezés. EXISTS
egy subquery kifejezést vesz fel, és visszaadja true
, ha az al lekérdezés bármilyen sort visszaad. Ellenkező esetben a értéket adja false
vissza.
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, mindkét SELECT
WHERE
és záradékban használhatóEXISTS
. Ez a viselkedés nem hasonlít a T-SQL-hez, ahol egy logikai kifejezés csak szűrőkre korlátozódik.
Ha az EXISTS
al lekérdezés egyetlen értéket ad vissza, akkor a undefined
EXISTS
kiértékelése hamis lesz. Vegyük például az alábbi lekérdezést, amely nem ad vissza semmit.
SELECT VALUE
undefined
Ha a EXISTS
kifejezést és az előző lekérdezést használja segéd lekérdezésként, a kifejezés a következőt adja false
vissza: .
SELECT
EXISTS (SELECT VALUE undefined)
[
{
"$1": false
}
]
Ha az előző részkikérdezés ÉRTÉK kulcsszóját nem adja meg, a részkikérdezés egyetlen üres objektummal rendelkező tömbre lesz kiértékelve.
SELECT
undefined
[
{}
]
Ekkor a EXISTS
kifejezés kiértékeli true
a értéket, mivel az objektum ({}
) technikailag kilép.
SELECT
EXISTS (SELECT undefined)
[
{
"$1": true
}
]
A gyakori használati eset egy elem szűrése ARRAY_CONTAINS
egy tömbben lévő elem megléte alapján. Ebben az esetben ellenőrizzük, hogy a tags
tömb tartalmaz-e "külső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 egyenlő-e egy tömb bármely eleméhez. Ha összetettebb szűrőkre van szüksége a tömbtulajdonságokon, használja helyette a parancsot JOIN
.
Vegyük ezt a példaelemet egy olyan készletben, amelyben több elem is szerepel, amelyek mindegyike tartalmaz egy tömböt accessories
.
{
"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 és quantityOnHand
tulajdonságainak 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 eleme esetében a rendszer a tömbelemekkel együtt hajtja végre a keresztterméket. Ez a JOIN
művelet lehetővé teszi a tömbben lévő tulajdonságok szűrését. A lekérdezés kérelemegység-felhasználása azonban jelentős. Ha például 1000 elem minden tömbben 100 elemet tartalmazott, akkor a (100 000) értékre 1,000 x 100
bővül.
A használatával EXISTS
elkerülheti ezt a költséges termékközi terméket. Ebben a következő példában a lekérdezés az alkérdezé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 ki.
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 leképezé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 ARRAY
kifejezéssel tömbként vetítheti ki a lekérdezések eredményeit. Ezt a kifejezést csak a SELECT
lekérdezés záradékában használhatja.
Ezekhez a példákhoz 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 SELECT
használjuk.
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 albeké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 FROM
záradék után is jöhetnek a segéd 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"
}
]