Bilanciamento delle scritture e delle letture in un database

Bilanciamento delle scritture e delle letture in un database
Nel precedente Articolo Ho descritto il concetto e l'implementazione di un database costruito sulla base di funzioni, piuttosto che di tabelle e campi come nei database relazionali. Ha fornito molti esempi che mostrano i vantaggi di questo approccio rispetto a quello classico. Molti li hanno trovati non abbastanza convincenti.

In questo articolo mostrerò come questo concetto consenta di bilanciare in modo rapido e conveniente scritture e letture nel database senza alcuna modifica nella logica operativa. Si è tentato di implementare funzionalità simili nei moderni DBMS commerciali (in particolare Oracle e Microsoft SQL Server). Alla fine dell'articolo mostrerò che quello che hanno fatto, per usare un eufemismo, non ha funzionato molto bene.

descrizione

Come prima, per una migliore comprensione inizierò la descrizione con degli esempi. Diciamo che dobbiamo implementare una logica che restituisca un elenco di dipartimenti con il numero di dipendenti al loro interno e il loro stipendio totale.

In un database funzionale sarebbe simile a questo:

CLASS Department ‘Отдел’;
name ‘Наименование’ = DATA STRING[100] (Department);

CLASS Employee ‘Сотрудник’;
department ‘Отдел’ = DATA Department (Employee);
salary ‘Зарплата’ =  DATA NUMERIC[10,2] (Employee);

countEmployees ‘Кол-во сотрудников’ (Department d) = 
    GROUP SUM 1 IF department(Employee e) = d;
salarySum ‘Суммарная зарплата’ (Department d) = 
    GROUP SUM salary(Employee e) IF department(e) = d;

SELECT name(Department d), countEmployees(d), salarySum(d);

La complessità dell'esecuzione di questa query in qualsiasi DBMS sarà equivalente a O(numero di dipendenti)perché questo calcolo richiede la scansione dell'intera tabella dei dipendenti e il loro raggruppamento per reparto. Ci sarà anche qualche piccolo supplemento (crediamo che siano molti più dipendenti che reparti) a seconda del piano scelto O(registrare il numero di dipendenti) o O(numero di dipartimenti) per il raggruppamento e così via.

È chiaro che l'overhead di esecuzione può essere diverso in diversi DBMS, ma la complessità non cambierà in alcun modo.

Nell'implementazione proposta, il DBMS funzionale genererà una sottoquery che calcolerà i valori richiesti per il dipartimento, quindi effettuerà un JOIN con la tabella del dipartimento per ottenere il nome. Tuttavia per ogni funzione, in fase di dichiarazione, è possibile impostare uno speciale marcatore MATERIALIZZATO. Il sistema creerà automaticamente un campo corrispondente per ciascuna di queste funzioni. Quando si modifica il valore di una funzione, cambierà anche il valore del campo nella stessa transazione. Accedendo a questa funzione si accederà al campo precalcolato.

In particolare, se imposti MATERIALIZZATO per le funzioni contareI dipendenti и stipendioSum, verranno quindi aggiunti due campi alla tabella con l'elenco dei dipartimenti, che memorizzeranno il numero dei dipendenti e il loro stipendio totale. Ogni volta che si verifica un cambiamento nei dipendenti, nei loro stipendi o nelle affiliazioni ai dipartimenti, il sistema modificherà automaticamente i valori di questi campi. La query precedente accederà direttamente a questi campi e verrà eseguita in O(numero di dipartimenti).

Quali sono le restrizioni? Solo una cosa: una funzione del genere deve avere un numero finito di valori di input per i quali viene definito il suo valore. Altrimenti sarà impossibile costruire una tabella che memorizzi tutti i suoi valori, poiché non può esistere una tabella con un numero infinito di righe.

Esempio:

employeesCount ‘Количество сотрудников с зарплатой > N’ (Department d, NUMERIC[10,2] N) = 
    GROUP SUM salary(Employee e) IF department(e) = d AND salary(e) > N;

Questa funzione è definita per un numero infinito di valori di N (ad esempio, qualsiasi valore negativo è adatto). Pertanto, non è possibile inserirvi MATERIALIZED. Quindi questa è una limitazione logica, non tecnica (ovvero, non perché non siamo riusciti a implementarla). Altrimenti non ci sono restrizioni. È possibile utilizzare raggruppamenti, ordinamento, AND e OR, PARTITION, ricorsione, ecc.

Ad esempio, nel problema 2.2 dell'articolo precedente, puoi inserire MATERIALIZED su entrambe le funzioni:

bought 'Купил' (Customer c, Product p, INTEGER y) = 
    GROUP SUM sum(Detail d) IF 
        customer(order(d)) = c AND 
        product(d) = p AND 
        extractYear(date(order(d))) = y MATERIALIZED;
rating 'Рейтинг' (Customer c, Product p, INTEGER y) = 
    PARTITION SUM 1 ORDER DESC bought(c, p, y), p BY c, y MATERIALIZED;
SELECT contactName(Customer c), name(Product p) WHERE rating(c, p, 1997) < 3;

Il sistema stesso creerà una tabella con le chiavi di tipo , Prodotto и INTEGER, aggiungerà due campi e aggiornerà i valori dei campi in essi contenuti con eventuali modifiche. Quando verranno effettuate ulteriori chiamate a queste funzioni, queste non verranno calcolate, ma verranno letti i valori dai campi corrispondenti.

Utilizzando questo meccanismo è possibile, ad esempio, eliminare le ricorsioni (CTE) nelle query. In particolare, consideriamo i gruppi che formano un albero utilizzando la relazione figlio/genitore (ogni gruppo ha un collegamento al suo genitore):

parent = DATA Group (Group);

In un database funzionale, la logica di ricorsione può essere specificata come segue:

level (Group child, Group parent) = RECURSION 1l IF child IS Group AND parent == child
                                                             STEP 2l IF parent == parent($parent);
isParent (Group child, Group parent) = TRUE IF level(child, parent) MATERIALIZED;

Poiché per la funzione isParent è contrassegnato come MATERIALIZZATO, verrà creata una tabella con due chiavi (gruppi) in cui il campo isParent sarà vero solo se la prima chiave è figlia della seconda. Il numero di voci in questa tabella sarà uguale al numero di gruppi moltiplicato per la profondità media dell'albero. Se hai bisogno, ad esempio, di contare il numero di discendenti di un certo gruppo, puoi utilizzare questa funzione:

childrenCount (Group g) = GROUP SUM 1 IF isParent(Group child, g);

Non ci sarà alcun CTE nella query SQL. Invece ci sarà un semplice GRUPPO PER.

Utilizzando questo meccanismo, puoi anche denormalizzare facilmente il database, se necessario:

CLASS Order 'Заказ';
date 'Дата' = DATA DATE (Order);

CLASS OrderDetail 'Строка заказа';
order 'Заказ' = DATA Order (OrderDetail);
date 'Дата' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED;

Quando si chiama una funzione quando per la riga d'ordine, dalla tabella delle righe d'ordine verrà letto il campo per il quale è presente l'indice. Quando la data dell'ordine cambia, il sistema stesso ricalcolerà automaticamente la data denormalizzata nella riga.

Vantaggi

A cosa serve tutto questo meccanismo? Nei DBMS classici, senza riscrivere le query, uno sviluppatore o un DBA può solo modificare gli indici, determinare le statistiche e dire al pianificatore delle query come eseguirle (e gli HINT sono disponibili solo nei DBMS commerciali). Non importa quanto ci provino, non saranno in grado di completare la prima query nell'articolo in O (numero di dipartimenti) senza modificare le query o aggiungere trigger. Nello schema proposto, in fase di sviluppo non è necessario pensare alla struttura di archiviazione dei dati e a quali aggregazioni utilizzare. Tutto questo può essere facilmente modificato al volo, direttamente durante il funzionamento.

In pratica sembra così. Alcune persone sviluppano la logica direttamente in base al compito da svolgere. Non comprendono gli algoritmi e la loro complessità, né i piani di esecuzione, né i tipi di join, né qualsiasi altro componente tecnico. Queste persone sono più analisti aziendali che sviluppatori. Quindi, tutto questo va in fase di test o funzionamento. Abilita la registrazione di query con esecuzione prolungata. Quando viene rilevata una query lunga, altre persone (più tecniche, essenzialmente DBA) decidono di abilitare MATERIALIZED su alcune funzioni intermedie. Ciò rallenta leggermente la registrazione (poiché richiede l'aggiornamento di un campo aggiuntivo nella transazione). Tuttavia non solo questa interrogazione viene notevolmente velocizzata, ma anche tutte le altre che utilizzano questa funzione. Allo stesso tempo, decidere quale funzione materializzare è relativamente facile. Due parametri principali: il numero di possibili valori di input (questo è quanti record saranno nella tabella corrispondente) e quanto spesso viene utilizzato in altre funzioni.

analoghi

I moderni DBMS commerciali hanno meccanismi simili: VISTA MATERIALIZZATA con FAST REFRESH (Oracle) e VISTA INDICE (Microsoft SQL Server). In PostgreSQL, la VISUALIZZAZIONE MATERIALIZZATA non può essere aggiornata in una transazione, ma solo su richiesta (e anche con restrizioni molto rigide), quindi non la consideriamo. Ma presentano diversi problemi che ne limitano notevolmente l’utilizzo.

Innanzitutto, puoi abilitare la materializzazione solo se hai già creato una VISTA normale. Altrimenti, dovrai riscrivere le restanti richieste per accedere alla vista appena creata per utilizzare questa materializzazione. Oppure lascia tutto così com'è, ma almeno sarà inefficace se ci sono alcuni dati già precalcolati, ma molte query non sempre li utilizzano, ma li ricalcolano.

In secondo luogo, hanno un numero enorme di restrizioni:

Oracle

5.3.8.4 Restrizioni generali sull'aggiornamento rapido

La query di definizione della vista materializzata è limitata come segue:

  • La vista materializzata non deve contenere riferimenti a espressioni non ripetitive come SYSDATE ed ROWNUM.
  • La vista materializzata non deve contenere riferimenti a RAW or LONG RAW tipi di dati.
  • Non può contenere a SELECT sottoquery elenco.
  • Non può contenere funzioni analitiche (ad esempio, RANK) nel Programma SELECT clausola.
  • Non può fare riferimento a una tabella su cui è presente un file XMLIndex l'indice è definito.
  • Non può contenere a MODEL clausola.
  • Non può contenere a HAVING clausola con una sottoquery.
  • Non può contenere query nidificate che hanno ANY, ALL, o NOT EXISTS.
  • Non può contenere a [START WITH …] CONNECT BY clausola.
  • Non può contenere più tabelle di dettaglio in siti diversi.
  • ON COMMIT le viste materializzate non possono avere tabelle di dettagli remote.
  • Le viste materializzate nidificate devono avere un join o un'aggregazione.
  • Viste join materializzate e viste aggregate materializzate con a GROUP BY la clausola non può selezionare da una tabella organizzata per indice.

5.3.8.5 Restrizioni sull'aggiornamento rapido su viste materializzate solo con join

La definizione di query per viste materializzate solo con join e senza aggregazioni presenta le seguenti restrizioni sull'aggiornamento rapido:

  • Tutte le restrizioni da «Restrizioni generali sull'aggiornamento rapido«.
  • Non possono avere GROUP BY clausole o aggregati.
  • Rowids di tutte le tabelle nel file FROM l'elenco deve apparire nel file SELECT elenco della query.
  • I log di visualizzazione materializzati devono esistere con rowid per tutte le tabelle di base nel file FROM elenco della query.
  • Non è possibile creare una vista materializzata aggiornabile rapidamente da più tabelle con join semplici che includono una colonna di tipo oggetto nel file SELECT .

Inoltre, il metodo di aggiornamento scelto non sarà efficiente in modo ottimale se:

  • La query di definizione utilizza un join esterno che si comporta come un join interno. Se la query di definizione contiene un join di questo tipo, valuta la possibilità di riscrivere la query di definizione per contenere un join interno.
  • I SELECT L'elenco della vista materializzata contiene espressioni su colonne di più tabelle.

5.3.8.6 Restrizioni sull'aggiornamento rapido su viste materializzate con aggregati

La definizione di query per viste materializzate con aggregazioni o join presenta le seguenti restrizioni sull'aggiornamento rapido:

L'aggiornamento rapido è supportato per entrambi ON COMMIT ed ON DEMAND viste materializzate, tuttavia si applicano le seguenti restrizioni:

  • Tutte le tabelle nella vista materializzata devono avere log di vista materializzati e i log di vista materializzati devono:
    • Contengono tutte le colonne della tabella a cui si fa riferimento nella vista materializzata.
    • Specificare con ROWID ed INCLUDING NEW VALUES.
    • specificare la SEQUENCE clausola se si prevede che la tabella contenga una combinazione di inserimenti/caricamenti diretti, eliminazioni e aggiornamenti.

  • Solo SUM, COUNT, AVG, STDDEV, VARIANCE, MIN ed MAX sono supportati per l'aggiornamento rapido.
  • COUNT(*) deve essere specificato.
  • Le funzioni aggregate devono essere presenti solo come parte più esterna dell'espressione. Cioè, aggregati come AVG(AVG(x)) or AVG(x)+ AVG(x) non sono consentiti.
  • Per ogni aggregato come AVG(expr), il corrispondente COUNT(expr) deve essere presente. Oracle lo consiglia SUM(expr) essere specificato.
  • If VARIANCE(expr) or STDDEV(expr) è specificato, COUNT(expr) ed SUM(expr) deve essere specificato. Oracle lo consiglia SUM(expr *expr) essere specificato.
  • I SELECT La colonna nella query di definizione non può essere un'espressione complessa con colonne provenienti da più tabelle di base. Una possibile soluzione a questo problema consiste nell'utilizzare una vista materializzata nidificata.
  • I SELECT l'elenco deve contenere tutti GROUP BY colonne.
  • La vista materializzata non è basata su una o più tabelle remote.
  • Se si utilizza un CHAR tipo di dati nelle colonne filtro di un log di vista materializzata, i set di caratteri del sito master e della vista materializzata devono essere gli stessi.
  • Se la vista materializzata ha uno dei seguenti, l'aggiornamento rapido è supportato solo sugli inserti DML convenzionali e sui caricamenti diretti.
    • Viste materializzate con MIN or MAX aggregati
    • Viste materializzate che hanno SUM(expr) ma no COUNT(expr)
    • Viste materializzate senza COUNT(*)

    Tale vista materializzata è chiamata vista materializzata di solo inserimento.

  • Una vista materializzata con MAX or MIN è aggiornabile rapidamente dopo l'eliminazione o istruzioni DML miste se non dispone di un file WHERE clausola.
    L'aggiornamento rapido massimo/minimo dopo l'eliminazione o il DML misto non ha lo stesso comportamento del caso di solo inserimento. Cancella e ricalcola i valori massimi/minimi per i gruppi interessati. È necessario essere consapevoli del suo impatto sulle prestazioni.
  • Viste materializzate con viste denominate o sottoquery nel file FROM La clausola può essere aggiornata rapidamente a condizione che le visualizzazioni possano essere completamente unite. Per informazioni su quali visualizzazioni verranno unite, vedere Riferimento al linguaggio SQL del database Oracle.
  • Se non sono presenti join esterni, potresti avere selezioni e join arbitrari nel file WHERE clausola.
  • Le viste aggregate materializzate con giunti esterni possono essere aggiornate rapidamente dopo DML convenzionale e carichi diretti, a condizione che sia stata modificata solo la tabella esterna. Inoltre, devono esistere vincoli univoci sulle colonne di join della tabella inner join. Se sono presenti join esterni, tutti i join devono essere collegati tramite ANDs e deve utilizzare l'uguaglianza (=) operatore.
  • Per viste materializzate con CUBE, ROLLUP, raggruppamenti o concatenazioni di essi, si applicano le seguenti restrizioni:
    • I SELECT list dovrebbe contenere un distintivo di raggruppamento che può essere a GROUPING_ID funzione su tutti GROUP BY espressioni o GROUPING funziona uno per ciascuno GROUP BY espressione. Ad esempio, se il GROUP BY clausola della vista materializzata è "GROUP BY CUBE(a, b)", poi il SELECT l'elenco dovrebbe contenere "GROUPING_ID(a, b)" o "GROUPING(a) AND GROUPING(b)» affinché la vista materializzata sia rapidamente aggiornabile.
    • GROUP BY non dovrebbe comportare raggruppamenti duplicati. Per esempio, "GROUP BY a, ROLLUP(a, b)" non è aggiornabile velocemente perché risulta in raggruppamenti duplicati "(a), (a, b), AND (a)«.

5.3.8.7 Restrizioni sull'aggiornamento rapido su viste materializzate con UNION ALL

Viste materializzate con il UNION ALL impostare il supporto dell'operatore REFRESH FAST opzione se sono soddisfatte le seguenti condizioni:

  • La query di definizione deve avere l'estensione UNION ALL operatore al massimo livello.

    I UNION ALL l'operatore non può essere incorporato in una sottoquery, con un'eccezione: l' UNION ALL può trovarsi in una sottoquery in FROM clausola a condizione che la query di definizione sia nel formato SELECT * FROM (visualizza o sottoquery con UNION ALL) come nell'esempio seguente:

    CREATE VIEW view_with_unionall AS (SELECT c.rowid crid, c.cust_id, 2 umarker FROM clienti c WHERE c.cust_last_name = 'Smith' UNION ALL SELECT c.rowid crid, c.cust_id, 3 umarker FROM clienti c WHERE c.cust_last_name = "Jones"); CREA VISTA MATERIALIZZATA unionall_inside_view_mv AGGIORNA VELOCEMENTE SU RICHIESTA COME SELECT * FROM view_with_unionall;
    

    Si noti che la vista view_with_unionall soddisfa i requisiti per l'aggiornamento rapido.

  • Ogni blocco di query nel file UNION ALL la query deve soddisfare i requisiti di una vista materializzata aggiornabile rapidamente con aggregati o di una vista materializzata aggiornabile rapidamente con join.

    È necessario creare i log di vista materializzata appropriati sulle tabelle come richiesto per il tipo corrispondente di vista materializzata ad aggiornamento rapido.
    Si noti che il database Oracle consente anche il caso speciale di una vista materializzata di una singola tabella con join solo a condizione che ROWID la colonna è stata inclusa nel file SELECT elenco e nel registro di visualizzazione materializzato. Questo è mostrato nella query di definizione della vista view_with_unionall.

  • I SELECT l'elenco di ciascuna query deve includere a UNION ALL marcatore e il UNION ALL colonna deve avere in ciascuna un valore numerico o stringa costante distinto UNION ALL ramo. Inoltre, la colonna marcatore deve apparire nella stessa posizione ordinale nel file SELECT elenco di ciascun blocco di query. Vedere "UNION ALL Marker e riscrittura delle query» per ulteriori informazioni riguardo UNION ALL marcatori.
  • Alcune funzionalità come i join esterni, le query di visualizzazione materializzata aggregata di solo inserimento e le tabelle remote non sono supportate per le viste materializzate con UNION ALL. Si noti, tuttavia, che le viste materializzate utilizzate nella replica, che non contengono join o aggregazioni, possono essere aggiornate rapidamente quando UNION ALL o vengono utilizzate tabelle remote.
  • Il parametro di inizializzazione della compatibilità deve essere impostato su 9.2.0 o versione successiva per creare una vista materializzata aggiornabile rapidamente UNION ALL.

Non voglio offendere i fan di Oracle, ma a giudicare dal loro elenco di restrizioni, sembra che questo meccanismo sia stato scritto non in un caso generale, utilizzando una sorta di modello, ma da migliaia di indiani, dove a tutti è stata data l'opportunità di scrivere il proprio ramo, e ognuno di loro ha fatto quello che poteva e lo ha fatto. Usare questo meccanismo per la logica reale è come camminare in un campo minato. Puoi ottenere una mina in qualsiasi momento colpendo una delle restrizioni non ovvie. Anche il modo in cui funziona è una questione separata, ma va oltre lo scopo di questo articolo.

Microsoft SQL Server

Requisiti aggiuntivi

Oltre alle opzioni SET e ai requisiti della funzione deterministica, devono essere soddisfatti i seguenti requisiti:

  • L'utente che esegue CREATE INDEX deve essere il proprietario della vista.
  • Quando crei l'indice, il file IGNORE_DUP_KEY l'opzione deve essere impostata su OFF (l'impostazione predefinita).
  • Le tabelle devono essere referenziate con nomi composti da due parti, schema.nometabella nella definizione della vista.
  • Le funzioni definite dall'utente a cui si fa riferimento nella vista devono essere create utilizzando il file WITH SCHEMABINDING opzione.
  • Qualsiasi funzione definita dall'utente a cui si fa riferimento nella vista deve essere referenziata con nomi composti da due parti, ..
  • La proprietà di accesso ai dati di una funzione definita dall'utente deve essere NO SQLe la proprietà di accesso esterno deve essere NO.
  • Le funzioni Common Language Runtime (CLR) possono essere visualizzate nell'elenco di selezione della vista, ma non possono far parte della definizione della chiave dell'indice cluster. Le funzioni CLR non possono essere visualizzate nella clausola WHERE della vista o nella clausola ON di un'operazione JOIN nella vista.
  • Le funzioni e i metodi CLR dei tipi CLR definiti dall'utente utilizzati nella definizione della vista devono avere le proprietà impostate come illustrato nella tabella seguente.

    Immobili
    Note:

    DETERMINISTICO = VERO
    Deve essere dichiarato esplicitamente come attributo del metodo Microsoft .NET Framework.

    PRECISO = VERO
    Deve essere dichiarato in modo esplicito come attributo del metodo .NET Framework.

    ACCESSO AI DATI = NESSUN SQL
    Determinato impostando l'attributo DataAccess su DataAccessKind.None e l'attributo SystemDataAccess su SystemDataAccessKind.None.

    ACCESSO ESTERNO = NO
    Per impostazione predefinita questa proprietà è NO per le routine CLR.

  • La vista deve essere creata utilizzando il file WITH SCHEMABINDING opzione.
  • La vista deve fare riferimento solo alle tabelle di base che si trovano nello stesso database della vista. La vista non può fare riferimento ad altre viste.
  • L'istruzione SELECT nella definizione della vista non deve contenere i seguenti elementi Transact-SQL:

    COUNT
    Funzioni ROWSET (OPENDATASOURCE, OPENQUERY, OPENROWSET, E OPENXML)
    OUTER si unisce (LEFT, RIGHT, o FULL)

    Tabella derivata (definita specificando a SELECT dichiarazione in FROM clausola)
    Auto-unione
    Specificare le colonne utilizzando SELECT * or SELECT <table_name>.*

    DISTINCT
    STDEV, STDEVP, VAR, VARP, o AVG
    Espressione di tabella comune (CTE)

    galleggiante1, testo, ntext, Immagine, XML, o filestream colonne
    sottoquery
    OVER clausola, che include funzioni di classificazione o di finestra aggregata

    Predicati full-text (CONTAINS, FREETEXT)
    SUM funzione che fa riferimento a un'espressione nullable
    ORDER BY

    Funzione di aggregazione CLR definita dall'utente
    TOP
    CUBE, ROLLUP, o GROUPING SETS Operatori

    MIN, MAX
    UNION, EXCEPT, o INTERSECT Operatori
    TABLESAMPLE

    Variabili di tabella
    OUTER APPLY or CROSS APPLY
    PIVOT, UNPIVOT

    Insiemi di colonne sparse
    Funzioni in linea (TVF) o con valori di tabella a istruzioni multiple (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 La vista indicizzata può contenere galleggiante colonne; tuttavia, tali colonne non possono essere incluse nella chiave dell'indice cluster.

  • If GROUP BY è presente, la definizione VIEW deve contenere COUNT_BIG(*) e non deve contenere HAVING. Queste GROUP BY le restrizioni sono applicabili solo alla definizione della vista indicizzata. Una query può utilizzare una vista indicizzata nel proprio piano di esecuzione anche se non li soddisfa GROUP BY restrizioni.
  • Se la definizione della vista contiene un file GROUP BY clausola, la chiave dell'indice cluster univoco può fare riferimento solo alle colonne specificate nella clausola GROUP BY clausola.

Qui è chiaro che gli indiani non sono stati coinvolti, poiché hanno deciso di farlo secondo lo schema “faremo poco, ma bene”. Cioè, hanno più mine sul campo, ma la loro posizione è più trasparente. La cosa più deludente è questa limitazione:

La vista deve fare riferimento solo alle tabelle di base che si trovano nello stesso database della vista. La vista non può fare riferimento ad altre viste.

Nella nostra terminologia, ciò significa che una funzione non può accedere a un'altra funzione materializzata. Ciò abbatte sul nascere ogni ideologia.
Inoltre, questa limitazione (e ulteriormente nel testo) riduce notevolmente i casi d'uso:

L'istruzione SELECT nella definizione della vista non deve contenere i seguenti elementi Transact-SQL:

COUNT
Funzioni ROWSET (OPENDATASOURCE, OPENQUERY, OPENROWSET, E OPENXML)
OUTER si unisce (LEFT, RIGHT, o FULL)

Tabella derivata (definita specificando a SELECT dichiarazione in FROM clausola)
Auto-unione
Specificare le colonne utilizzando SELECT * or SELECT <table_name>.*

DISTINCT
STDEV, STDEVP, VAR, VARP, o AVG
Espressione di tabella comune (CTE)

galleggiante1, testo, ntext, Immagine, XML, o filestream colonne
sottoquery
OVER clausola, che include funzioni di classificazione o di finestra aggregata

Predicati full-text (CONTAINS, FREETEXT)
SUM funzione che fa riferimento a un'espressione nullable
ORDER BY

Funzione di aggregazione CLR definita dall'utente
TOP
CUBE, ROLLUP, o GROUPING SETS Operatori

MIN, MAX
UNION, EXCEPT, o INTERSECT Operatori
TABLESAMPLE

Variabili di tabella
OUTER APPLY or CROSS APPLY
PIVOT, UNPIVOT

Insiemi di colonne sparse
Funzioni in linea (TVF) o con valori di tabella a istruzioni multiple (MSTVF)
OFFSET

CHECKSUM_AGG

OUTER JOINS, UNION, ORDER BY e altri sono vietati. Forse sarebbe stato più semplice specificare cosa poteva essere utilizzato piuttosto che cosa non poteva essere utilizzato. Probabilmente l’elenco sarebbe molto più breve.

Per riassumere: un’enorme serie di restrizioni in ogni DBMS (notiamo commerciale) contro nessuna (ad eccezione di una logica, non tecnica) nella tecnologia LGPL. Tuttavia, va notato che l'implementazione di questo meccanismo nella logica relazionale è leggermente più difficile che nella logica funzionale descritta.

implementazione

Come funziona? PostgreSQL viene utilizzato come una “macchina virtuale”. All'interno è presente un algoritmo complesso che crea query. Qui codice sorgente. E non esiste solo un ampio insieme di euristiche con un mucchio di se. Quindi, se hai un paio di mesi per studiare, puoi provare a capire l'architettura.

Funziona in modo efficace? Abbastanza efficace. Sfortunatamente, questo è difficile da dimostrare. Posso solo dire che se consideriamo le migliaia di query presenti nelle applicazioni di grandi dimensioni, in media sono più efficienti di quelle di un buon sviluppatore. Un eccellente programmatore SQL può scrivere qualsiasi query in modo più efficiente, ma con mille query semplicemente non avrà la motivazione o il tempo per farlo. L'unica cosa che ora posso citare come prova dell'efficacia è che diversi progetti stanno lavorando sulla piattaforma costruita su questo DBMS Sistemi ERP, che hanno migliaia di diverse funzioni MATERIALIZZATE, con migliaia di utenti e database di terabyte con centinaia di milioni di record in esecuzione su un normale server a due processori. Tuttavia, chiunque può verificarne/confutare l'efficacia scaricandolo una piattaforma e PostgreSQL, acceso registrando query SQL e tentando di modificare la logica e i dati lì.

Nei seguenti articoli parlerò anche di come impostare restrizioni sulle funzioni, lavorare con sessioni di modifica e molto altro.

Fonte: habr.com

Aggiungi un commento