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ő 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ó 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 backstock
false
. Az JOIN
itt szereplő kifejezés minden egyező elem összes elemének kereszt-szorzatát warehouseStock
tags
onHandQuantities
hajtja 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 10
bő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 SELECT
WHERE
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": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"name": "Winter glove"
},
{
"id": "bbbbbbbb-1111-2222-3333-cccccccccccc"
},
{
"id": "cccccccc-2222-3333-4444-dddddddddddd"
}
]
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 undefined
ad 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"
}
]