---
term: 'Query sul database e linguaggi di query'
seoTitle: 'Query sul database: linguaggi di query spiegati'
headline: 'Che cos''è una query sul database?'
slug: query-sul-database
category: database
shortDefinition: 'Una query sul database è una richiesta strutturata di dati – filtrare, ordinare, proiettare, paginare – scritta in un linguaggio che il motore esegue.'
relatedTerms:
  - database-index
  - n-plus-one-query-problem
  - relational-queries-document-databases
  - graphql-vs-rest
contrastsWith:
  - auto-generated-database-apis
faq:
  - question: 'Che cos''è una query sul database in parole semplici?'
    answer: 'Una richiesta strutturata che chiede al database di recuperare o modificare dati – "dammi gli articoli pubblicati con più di mille visualizzazioni, dal più recente, venti alla volta". Si scrive in un linguaggio di query oppure si costruisce con un SDK, segue una sintassi rigorosa perché il motore possa analizzarla e restituisce esattamente la porzione di dati che descrive.'
  - question: 'SQL è dichiarativo o imperativo?'
    answer: 'Dichiarativo – si dichiara quali dati servono, e l''ottimizzatore del motore decide come recuperarli: quali indici usare, quale ordine dei join, quale algoritmo. Quella divisione del lavoro è l''idea centrale delle query moderne, e vale oltre SQL: anche le API di query documentali e GraphQL sono dichiarative. Il codice imperativo cicla sui record; le query dichiarative descrivono i risultati.'
  - question: 'Come viene eseguita davvero una query?'
    answer: 'Una pipeline in quattro fasi: il motore analizza il testo e ne ricava un albero sintattico, lo valida rispetto allo schema, pianifica e ottimizza – scegliendo indici, ordine dei join e algoritmi per costo stimato – poi esegue il piano scelto e restituisce i risultati in streaming. Il piano è ispezionabile: EXPLAIN mostra esattamente ciò che ha deciso l''ottimizzatore, ed è da lì che parte ogni debug delle prestazioni.'
  - question: 'Qual è l''anatomia di una query?'
    answer: 'Cinque verbi coprono quasi tutto: filtrare (quali record – WHERE), ordinare (in che ordine – ORDER BY), proiettare (quali campi – la lista del SELECT), paginare (quanti, da dove – LIMIT/OFFSET oppure un cursore) e aggregare (sintesi calcolate – GROUP BY). Ogni linguaggio di query e ogni SDK esprime questi stessi cinque verbi; cambia solo la sintassi.'
  - question: 'Come rendono rapide le query gli indici?'
    answer: 'Sostituiscono la scansione con la ricerca: invece di leggere ogni record per trovare le corrispondenze (costo lineare nella dimensione della tabella), il motore percorre una struttura ordinata fino a esse (costo logaritmico). La differenza è invisibile su mille righe ed è decisiva su dieci milioni. EXPLAIN rivela quale dei due comportamenti si sta ottenendo – una scansione sequenziale su una tabella grande è il classico campanello d''allarme.'
  - question: 'Che cos''è la SQL injection e come la prevengono le query parametrizzate?'
    answer: 'L''injection è un input ostile che cambia la struttura di una query – i classici trucchi con apici e commenti che trasformano un controllo di accesso in una tautologia. Le query parametrizzate chiudono il buco separando il codice dai dati: il testo della query contiene segnaposto, i valori vengono associati a parte e l''input viene trattato sempre e solo come valore, mai analizzato come sintassi. SDK e query builder parametrizzano per costruzione.'
  - question: 'Qual è la differenza tra paginazione per offset e per cursore?'
    answer: 'La paginazione per offset (salta N, prendi 20) è semplice e permette di arrivare a qualunque pagina, ma il motore deve contare e scartare le righe saltate – la pagina 500 costa più della pagina 1 – e le scritture concorrenti possono spostare i risultati tra le pagine. La paginazione per cursore ("dopo questa chiave, prendi 20") resta rapida e stabile a qualunque profondità, al prezzo di non poter saltare a una pagina arbitraria. I feed vogliono i cursori; per le piccole tabelle di amministrazione l''offset va benissimo.'
  - question: 'Gli SDK e i query builder sostituiscono la conoscenza delle query?'
    answer: 'Sostituiscono la scrittura della sintassi, non la comprensione della semantica. Una catena di builder compila nella stessa anatomia filtra-ordina-proietta-pagina e sfrutta gli stessi indici – oppure li manca. Il fallimento classico è il pattern N+1: una query per elemento dentro un ciclo, invisibile nel codice e brutale in produzione. L''anatomia e il modello di costo si trasferiscono a ogni superficie.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'Query language (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Query_language'
  - name: 'PostgreSQL — Using EXPLAIN'
    url: 'https://www.postgresql.org/docs/current/using-explain.html'
  - name: 'GraphQL specification and docs'
    url: 'https://graphql.org/learn/'
  - name: 'SDK query documentation'
    url: 'https://docs.parseplatform.org/js/guide/#queries'
cta:
  title: 'Query senza il linguaggio di query'
  text: 'Su Back4app il query builder di ogni SDK compila query indicizzate e parametrizzate sui tuoi dati – gli stessi cinque verbi, nessuna superficie di injection, più GraphQL quando i client vogliono chiedere esattamente ciò che serve loro.'
  linkText: 'Inizia gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-10-09'
translationKey: database-queries
---

**Una query sul database è una richiesta strutturata di dati – filtrare, ordinare, proiettare, paginare – scritta in un linguaggio che il motore esegue.** L'idea profonda sotto ogni linguaggio di query è la *dichiaratività*: si descrive il risultato, e il motore sceglie il percorso. Basta padroneggiare una volta i cinque verbi e il modello di costo, e ogni sintassi – SQL, API documentali, GraphQL, builder degli SDK – diventa un accento, non una lingua nuova.

## Punti chiave

| Domanda | Risposta |
| --- | --- |
| Che cos'è | Una richiesta precisa: quali record, in che ordine, quali campi, quanti |
| Il paradigma | Dichiarativo – si dice *che cosa*; l'ottimizzatore decide *come* |
| La pipeline | Analisi → validazione → pianificazione/ottimizzazione → esecuzione |
| Il modello di costo | Ricerca tramite indice vs. scansione completa – EXPLAIN dice quale dei due |
| La regola di sicurezza | Parametrizzare sempre; mai concatenare un input dentro una query |

## La stessa query in quattro linguaggi di query

La stessa richiesta – *articoli pubblicati, oltre 1.000 visualizzazioni, dal più recente* – attraverso le famiglie di linguaggi:

```sql
-- SQL: il dichiarativo originale
SELECT title, views FROM articles
WHERE  status = 'published' AND views > 1000
ORDER  BY published_at DESC
LIMIT  20;
```

```javascript
// API di query documentale
db.articles.find(
  { status: 'published', views: { $gt: 1000 } },  // filtrare
  { title: 1, views: 1 }                          // proiettare
).sort({ publishedAt: -1 }).limit(20)

// GraphQL: i client dichiarano la forma che vogliono ricevere
query {
  articles(where: { status: "published", views_gt: 1000 },
           orderBy: publishedAt_DESC, first: 20) {
    title
    views
  }
}
```

E il builder dell'SDK – la superficie che il codice applicativo usa davvero, compilata nella stessa anatomia:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// Filter, sort, project, paginate — the full anatomy in one query
const query = new Parse.Query('Article');
query.equalTo('status', 'published');       // filter
query.greaterThan('views', 1000);           // filter (range)
query.descending('publishedAt');            // sort
query.select('title', 'views');             // project: only these fields
query.limit(20).skip(40);                   // paginate: page 3
const articles = await query.find();
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Filter, sort, project, paginate — the full anatomy in one query
final query = QueryBuilder<ParseObject>(ParseObject('Article'))
  ..whereEqualTo('status', 'published')     // filter
  ..whereGreaterThan('views', 1000)         // filter (range)
  ..orderByDescending('publishedAt')        // sort
  ..keysToReturn(['title', 'views'])        // project: only these fields
  ..setLimit(20)..setAmountToSkip(40);      // paginate: page 3
final response = await query.query();
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// Filter, sort, project, paginate — the full anatomy in one query
let query = Article.query("status" == "published", "views" > 1000)
  .order([.descending("publishedAt")])      // sort
  .select("title", "views")                 // project: only these fields
  .limit(20).skip(40)                       // paginate: page 3
query.find { result in
  if case .success(let articles) = result { render(articles) }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// Filter, sort, project, paginate — the full anatomy in one query
val query = ParseQuery.getQuery<ParseObject>("Article")
query.whereEqualTo("status", "published")   // filter
query.whereGreaterThan("views", 1000)       // filter (range)
query.orderByDescending("publishedAt")      // sort
query.selectKeys(listOf("title", "views"))  // project: only these fields
query.limit = 20; query.skip = 40           // paginate: page 3
query.findInBackground { articles, e -> if (e == null) render(articles) }
```

## Come un database esegue una query

```mermaid
flowchart LR
  accTitle: Pipeline di esecuzione di una query
  accDescr: Il motore analizza il testo della query per ricavarne un albero sintattico, lo valida rispetto allo schema, pianifica e ottimizza scegliendo indici e strategie di join in base al costo, poi esegue il piano e restituisce i risultati.
  Q["Testo della query"] --> P["Analisi<br/>albero sintattico"]
  P --> V["Validazione<br/>rispetto allo schema"]
  V --> O["Pianificazione e ottimizzazione<br/>indici · ordine dei join · costo"]
  O --> E["Esecuzione<br/>risultati in streaming"]
```

L'ottimizzatore è la ragione per cui le query dichiarative funzionano: pesa gli [indici](/glossary/it/indice-del-database/) disponibili, stima il numero di righe e sceglie il piano meno costoso – e [EXPLAIN](https://www.postgresql.org/docs/current/using-explain.html) ne mostra la decisione. Il metodo di performance in una riga: lanciare EXPLAIN, cercare la scansione completa, aggiungere l'indice che il filtro sta implorando, guardare di nuovo.

## Dichiarativo vs. imperativo

| Dimensione | Query dichiarativa | Codice imperativo |
| --- | --- | --- |
| Che cosa si scrive | Il risultato desiderato | I passi per calcolarlo |
| Chi ottimizza | Il motore, a ogni esecuzione | Chi scrive il codice, una volta sola |
| Si adatta al volume dei dati | Sì – i piani cambiano con le statistiche | No – il ciclo resta il ciclo |
| Dove vive | SQL, API documentali, GraphQL, builder | Cicli applicativi sui record |
| Sintomo di fallimento | Piano sbagliato (si corregge con indici/hint) | Cicli N+1, esplosioni di memoria |

L'anatomia che si ritrova in tutti: **filtrare** (`WHERE`), **ordinare** (`ORDER BY`), **proiettare** (la lista del SELECT – chiedere solo ciò che serve), **paginare** (`LIMIT` più offset o cursore), **aggregare** (`GROUP BY` e affini). Cinque verbi, tutte le superfici.

## Le due regole che evitano la maggior parte degli incidenti da query

**Parametrizzare, sempre.** L'injection è un input ostile che diventa *struttura* della query – un problema risolto del tutto da segnaposto che associano l'input come valore:

```javascript
// Vulnerabile: input concatenato nella struttura della query
db.query(`SELECT * FROM users WHERE name = '${input}'`);   // mai così

// Sicuro: parametrizzato – l'input è un dato, non sintassi
db.query('SELECT * FROM users WHERE name = $1', [input]);
```

I builder degli SDK e le variabili GraphQL lo fanno per costruzione – una delle vittorie silenziose, in termini di sicurezza, delle superfici di query di livello più alto.

**Paginare secondo la forma dell'accesso.** La paginazione per offset (`LIMIT 20 OFFSET 400`) permette di arrivare a qualunque pagina, ma paga la profondità in modo lineare e vacilla sotto le scritture concorrenti; la paginazione per cursore (`WHERE published_at < $last`) è stabile e a costo costante a qualunque profondità, ma avanza solo in un senso. Feed e scroll infinito vogliono i cursori; le tabelle di amministrazione numerate per pagina sono il terreno legittimo dell'offset.

## Casi d'uso tipici

- **Letture applicative.** Viste a elenco, schermate di dettaglio, ricerca – il quartetto filtra-ordina-proietta-pagina nel suo habitat naturale.
- **Aggregazione e reporting.** Conteggi, somme, sintesi raggruppate – spinti nel motore, dove stanno i dati, invece di essere calcolati nel codice applicativo.
- **Superfici di API.** Le [API generate automaticamente](/glossary/it/api-generate-automaticamente/) traducono parametri di URL o selezioni GraphQL in queste stesse query – l'anatomia traspare attraverso ogni astrazione.
- **Filtri in tempo reale.** Le sottoscrizioni live sono query permanenti – gli stessi predicati, valutati di continuo.
- **Fare debug in produzione.** EXPLAIN più il log delle query lente è il ciclo di diagnosi per la categoria di incidenti "è diventato lento".

## Linguaggio nativo, builder o SDK? Matrice decisionale

| Scegliere… | Quando… | Attenzione a… |
| --- | --- | --- |
| Il linguaggio di query nativo | Aggregazioni complesse, report, migrazioni | L'injection in caso di concatenazione; la portabilità |
| Un query builder / SDK | CRUD applicativo ed elenchi – quasi tutto il codice | I cicli N+1; i builder nascondono il piano |
| GraphQL | I client devono scegliere i campi e annidare le relazioni | Un costo di query non limitato in assenza di tetti |
| Logica memorizzata / lato server | Operazioni a più passi vicino ai dati | Logica nascosta fuori dalla codebase |

La regola onesta della [discussione sui livelli di astrazione](/glossary/it/livello-di-astrazione-del-database/) vale parola per parola: builder per il 90 % di routine, query native dove il controllo si ripaga – e la conoscenza dell'anatomia si trasferisce in entrambi i casi.

## Limiti e trade-off

- **Il dichiarativo non è gratuito.** L'ottimizzatore vale quanto valgono le sue statistiche e i suoi indici; una query giusta su indici sbagliati resta lenta.
- **Le query nascondono il proprio costo.** Una riga di catena del builder può essere una scansione su milioni di righe; EXPLAIN è l'unico specchio onesto.
- **La trappola N+1 vive sopra la query.** Query singole perfette, emesse dentro un ciclo, sono collettivamente patologiche – il batching e gli include esistono per questo.
- **La paginazione profonda degrada.** La profondità dell'offset ha costo lineare; conviene progettare i feed intorno ai cursori dal primo giorno.
- **La proliferazione dei linguaggi è reale.** SQL, API documentali, GraphQL, DSL di ricerca – ogni superficie costa una tassa al team; l'anatomia condivisa è l'antidoto.

## Le query su Back4app

Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. Il suo approccio alle query è la via del builder dell'SDK portata fino in fondo: il [query builder](https://docs.parseplatform.org/js/guide/#queries) di ogni SDK – i tab di codice qui sopra – compila filtrare, ordinare, proiettare e paginare in query parametrizzate senza superficie di injection, `include()` gestisce le relazioni senza cicli N+1, gli stessi predicati alimentano le [live queries](https://www.back4app.com) per gli aggiornamenti in tempo reale, e GraphQL serve i client che vogliono dichiarare la propria forma. Cinque verbi, tutte le superfici, un solo backend.
