Come velocizzare l'ordinamento ORDER BY quando si utilizza l'indice GIN in PostgreSQL?


12

Ho un tavolo come questo:

CREATE TABLE products (
  id serial PRIMARY KEY, 
  category_ids integer[],
  published boolean NOT NULL,
  score integer NOT NULL,
  title varchar NOT NULL);

Un prodotto può appartenere a più categorie. category_idscolonna contiene un elenco di ID di tutte le categorie di prodotti.

La query tipica è simile a questa (sempre alla ricerca di una singola categoria):

SELECT * FROM products WHERE published
  AND category_ids @> ARRAY[23465]
ORDER BY score DESC, title
LIMIT 20 OFFSET 8000;

Per accelerarlo uso il seguente indice:

CREATE INDEX idx_test1 ON products
  USING GIN (category_ids gin__int_ops) WHERE published;

Questo aiuta molto se non ci sono troppi prodotti in una categoria. Filtra rapidamente i prodotti che appartengono a quella categoria ma poi c'è un'operazione di ordinamento che deve essere fatta nel modo più duro (senza indice).

btree_ginUn'estensione installata mi consente di creare un indice GIN multi-colonna in questo modo:

CREATE INDEX idx_test2 ON products USING GIN (
  category_ids gin__int_ops, score, title) WHERE published;

Ma Postgres non vuole usarlo per l'ordinamento . Anche quando rimuovo l' DESCidentificatore nella query.

Qualsiasi approccio alternativo per ottimizzare l'attività è il benvenuto.


Informazioni aggiuntive:

  • PostgreSQL 9.4, con estensione intarray
  • il numero totale di prodotti attualmente è di 260.000 ma si prevede che cresca in modo significativo (fino a 10 milioni, questa è la piattaforma di e-commerce multi-tenant)
  • prodotti per categoria 1..10000 (può crescere fino a 100k), la media è inferiore a 100 ma quelle categorie con un gran numero di prodotti tendono ad attrarre molte più richieste

Il seguente piano di query è stato ottenuto da un sistema di test più piccolo (4680 prodotti nella categoria selezionata, 200.000 prodotti nella tabella):

Limit  (cost=948.99..948.99 rows=1 width=72) (actual time=82.330..82.341 rows=20 loops=1)
  ->  Sort  (cost=948.37..948.99 rows=245 width=72) (actual time=80.231..81.337 rows=4020 loops=1)
        Sort Key: score, title
        Sort Method: quicksort  Memory: 928kB
        ->  Bitmap Heap Scan on products  (cost=13.90..938.65 rows=245 width=72) (actual time=1.919..16.044 rows=4680 loops=1)
              Recheck Cond: ((category_ids @> '{292844}'::integer[]) AND published)
              Heap Blocks: exact=3441
              ->  Bitmap Index Scan on idx_test2  (cost=0.00..13.84 rows=245 width=0) (actual time=1.185..1.185 rows=4680 loops=1)
                    Index Cond: (category_ids @> '{292844}'::integer[])
Planning time: 0.202 ms
Execution time: 82.404 ms

Nota # 1 : 82 ms potrebbe non sembrare così spaventoso, ma è perché il buffer di ordinamento si adatta alla memoria. Dopo aver selezionato tutte le colonne dalla tabella dei prodotti ( SELECT * FROM ...e nella vita reale ci sono circa 60 colonne), il Sort Method: external merge Disk: 5696kBtempo di esecuzione raddoppia. E questo è solo per 4680 prodotti.

Punto d'azione n. 1 (deriva dalla nota n. 1): al fine di ridurre il footprint di memoria dell'operazione di ordinamento e quindi accelerarlo un po 'sarebbe saggio recuperare, ordinare e limitare prima gli ID del prodotto, quindi recuperare i record completi:

SELECT * FROM products WHERE id IN (
  SELECT id FROM products WHERE published AND category_ids @> ARRAY[23465]
  ORDER BY score DESC, title LIMIT 20 OFFSET 8000
) ORDER BY score DESC, title;

Questo ci riporta a Sort Method: quicksort Memory: 903kB~ 80 ms per 4680 prodotti. Può ancora essere lento quando il numero di prodotti raggiunge i 100k.


In questa pagina: hlinnaka.iki.fi/2014/03/28/… c'è un commento che btree_gin non può essere usato per l'ordinamento.
Mladen Uzelac,

OK, ho riformulato il titolo per consentire più opzioni.
Yaroslav Stavnichiy,

Sei sempre alla ricerca di una singola categoria? E fornisci alcune informazioni di base: versione di Postgres, cardinalità, righe per categoria (min / avg / max). considerare le istruzioni nelle informazioni sui tag per postgresql-performance . E: scorepuò essere NULL, ma si ordina comunque score DESC, non score DESC NULLS LAST. L'uno o l'altro non sembra giusto ...
Erwin Brandstetter,

Ho aggiunto ulteriori informazioni come richiesto. Sono sempre alla ricerca di una singola categoria. E scorein effetti NON è NULL - Ho corretto la definizione della tabella.
Yaroslav Stavnichiy,

Risposte:


9

Ho fatto molti esperimenti e qui ci sono le mie scoperte.

GIN e ordinamento

L'indice GIN al momento (dalla versione 9.4) non può essere d'aiuto per l'ordinazione .

Dei tipi di indice attualmente supportati da PostgreSQL, solo B-tree può produrre output ordinati - gli altri tipi di indice restituiscono le righe corrispondenti in un ordine non specificato, dipendente dall'implementazione.

work_mem

Grazie Chris per aver segnalato questo parametro di configurazione . L'impostazione predefinita è 4 MB e, nel caso in cui il recordset sia più grande, aumentando work_memal valore corretto (reperibile da EXPLAIN ANALYSE) è possibile velocizzare notevolmente le operazioni di ordinamento.

ALTER SYSTEM SET work_mem TO '32MB';

Riavvia il server per rendere effettive le modifiche, quindi ricontrolla:

SHOW work_mem;

Query originale

Ho popolato il mio database con 650k prodotti con alcune categorie che possono contenere fino a 40k prodotti. Ho semplificato un po 'le query rimuovendo la publishedclausola:

SELECT * FROM products WHERE category_ids @> ARRAY [248688]
ORDER BY score DESC, title LIMIT 10 OFFSET 30000;

Limit  (cost=2435.62..2435.62 rows=1 width=1390) (actual time=1141.254..1141.256 rows=10 loops=1)
  ->  Sort  (cost=2434.00..2435.62 rows=646 width=1390) (actual time=1115.706..1140.513 rows=30010 loops=1)
        Sort Key: score, title
        Sort Method: external merge  Disk: 29656kB
        ->  Bitmap Heap Scan on products  (cost=17.01..2403.85 rows=646 width=1390) (actual time=11.831..25.646 rows=41666 loops=1)
              Recheck Cond: (category_ids @> '{248688}'::integer[])
              Heap Blocks: exact=6471
              ->  Bitmap Index Scan on idx_products_category_ids_gin  (cost=0.00..16.85 rows=646 width=0) (actual time=10.140..10.140 rows=41666 loops=1)
                    Index Cond: (category_ids @> '{248688}'::integer[])
Planning time: 0.288 ms
Execution time: 1146.322 ms

Come possiamo vedere work_memnon è stato abbastanza, quindi abbiamo avuto Sort Method: external merge Disk: 29656kB(il numero qui è approssimativo, ha bisogno di poco più di 32 MB per quicksort in memoria).

Ridurre il footprint di memoria

Non selezionare record completi per l'ordinamento, utilizzare ID, applicare ordinamento, offset e limite, quindi caricare solo 10 record di cui abbiamo bisogno:

SELECT * FROM products WHERE id in (
  SELECT id FROM products WHERE category_ids @> ARRAY[248688]
  ORDER BY score DESC, title LIMIT 10 OFFSET 30000
) ORDER BY score DESC, title;

Sort  (cost=2444.10..2444.11 rows=1 width=1390) (actual time=707.861..707.862 rows=10 loops=1)
  Sort Key: products.score, products.title
  Sort Method: quicksort  Memory: 35kB
  ->  Nested Loop  (cost=2436.05..2444.09 rows=1 width=1390) (actual time=707.764..707.803 rows=10 loops=1)
        ->  HashAggregate  (cost=2435.63..2435.64 rows=1 width=4) (actual time=707.744..707.746 rows=10 loops=1)
              Group Key: products_1.id
              ->  Limit  (cost=2435.62..2435.62 rows=1 width=72) (actual time=707.732..707.734 rows=10 loops=1)
                    ->  Sort  (cost=2434.00..2435.62 rows=646 width=72) (actual time=704.163..706.955 rows=30010 loops=1)
                          Sort Key: products_1.score, products_1.title
                          Sort Method: quicksort  Memory: 7396kB
                          ->  Bitmap Heap Scan on products products_1  (cost=17.01..2403.85 rows=646 width=72) (actual time=11.587..35.076 rows=41666 loops=1)
                                Recheck Cond: (category_ids @> '{248688}'::integer[])
                                Heap Blocks: exact=6471
                                ->  Bitmap Index Scan on idx_products_category_ids_gin  (cost=0.00..16.85 rows=646 width=0) (actual time=9.883..9.883 rows=41666 loops=1)
                                      Index Cond: (category_ids @> '{248688}'::integer[])
        ->  Index Scan using products_pkey on products  (cost=0.42..8.45 rows=1 width=1390) (actual time=0.004..0.004 rows=1 loops=10)
              Index Cond: (id = products_1.id)
Planning time: 0.682 ms
Execution time: 707.973 ms

Nota Sort Method: quicksort Memory: 7396kB. Il risultato è molto meglio.

UNISCITI e indice B-tree aggiuntivo

Come ha consigliato Chris, ho creato un indice aggiuntivo:

CREATE INDEX idx_test7 ON products (score DESC, title);

Per prima cosa ho provato a unirmi in questo modo:

SELECT * FROM products NATURAL JOIN
  (SELECT id FROM products WHERE category_ids @> ARRAY[248688]
  ORDER BY score DESC, title LIMIT 10 OFFSET 30000) c
ORDER BY score DESC, title;

Il piano di query differisce leggermente ma il risultato è lo stesso:

Sort  (cost=2444.10..2444.11 rows=1 width=1390) (actual time=700.747..700.747 rows=10 loops=1)
  Sort Key: products.score, products.title
  Sort Method: quicksort  Memory: 35kB
  ->  Nested Loop  (cost=2436.05..2444.09 rows=1 width=1390) (actual time=700.651..700.690 rows=10 loops=1)
        ->  HashAggregate  (cost=2435.63..2435.64 rows=1 width=4) (actual time=700.630..700.630 rows=10 loops=1)
              Group Key: products_1.id
              ->  Limit  (cost=2435.62..2435.62 rows=1 width=72) (actual time=700.619..700.619 rows=10 loops=1)
                    ->  Sort  (cost=2434.00..2435.62 rows=646 width=72) (actual time=697.304..699.868 rows=30010 loops=1)
                          Sort Key: products_1.score, products_1.title
                          Sort Method: quicksort  Memory: 7396kB
                          ->  Bitmap Heap Scan on products products_1  (cost=17.01..2403.85 rows=646 width=72) (actual time=10.796..32.258 rows=41666 loops=1)
                                Recheck Cond: (category_ids @> '{248688}'::integer[])
                                Heap Blocks: exact=6471
                                ->  Bitmap Index Scan on idx_products_category_ids_gin  (cost=0.00..16.85 rows=646 width=0) (actual time=9.234..9.234 rows=41666 loops=1)
                                      Index Cond: (category_ids @> '{248688}'::integer[])
        ->  Index Scan using products_pkey on products  (cost=0.42..8.45 rows=1 width=1390) (actual time=0.004..0.004 rows=1 loops=10)
              Index Cond: (id = products_1.id)
Planning time: 1.015 ms
Execution time: 700.918 ms

Giocando con vari offset e conteggi dei prodotti non sono riuscito a fare in modo che PostgreSQL usasse un indice B-tree aggiuntivo.

Così sono andato in modo classico e ho creato una tabella di giunzione :

CREATE TABLE prodcats AS SELECT id AS product_id, unnest(category_ids) AS category_id FROM products;
CREATE INDEX idx_prodcats_cat_prod_id ON prodcats (category_id, product_id);

SELECT p.* FROM products p JOIN prodcats c ON (p.id=c.product_id)
WHERE c.category_id=248688
ORDER BY p.score DESC, p.title LIMIT 10 OFFSET 30000;

Limit  (cost=122480.06..122480.09 rows=10 width=1390) (actual time=1290.360..1290.362 rows=10 loops=1)
  ->  Sort  (cost=122405.06..122509.00 rows=41574 width=1390) (actual time=1264.250..1289.575 rows=30010 loops=1)
        Sort Key: p.score, p.title
        Sort Method: external merge  Disk: 29656kB
        ->  Merge Join  (cost=50.46..94061.13 rows=41574 width=1390) (actual time=117.746..182.048 rows=41666 loops=1)
              Merge Cond: (p.id = c.product_id)
              ->  Index Scan using products_pkey on products p  (cost=0.42..90738.43 rows=646067 width=1390) (actual time=0.034..116.313 rows=210283 loops=1)
              ->  Index Only Scan using idx_prodcats_cat_prod_id on prodcats c  (cost=0.43..1187.98 rows=41574 width=4) (actual time=0.022..7.137 rows=41666 loops=1)
                    Index Cond: (category_id = 248688)
                    Heap Fetches: 0
Planning time: 0.873 ms
Execution time: 1294.826 ms

Continuando a non utilizzare l'indice B-tree, il gruppo di risultati non si adattava work_mem, quindi scarsi risultati.

Ma in alcune circostanze, avendo un gran numero di prodotti e un piccolo offset PostgreSQL decide ora di utilizzare l'indice B-tree:

SELECT p.* FROM products p JOIN prodcats c ON (p.id=c.product_id)
WHERE c.category_id=248688
ORDER BY p.score DESC, p.title LIMIT 10 OFFSET 300;

Limit  (cost=3986.65..4119.51 rows=10 width=1390) (actual time=264.176..264.574 rows=10 loops=1)
  ->  Nested Loop  (cost=0.98..552334.77 rows=41574 width=1390) (actual time=250.378..264.558 rows=310 loops=1)
        ->  Index Scan using idx_test7 on products p  (cost=0.55..194665.62 rows=646067 width=1390) (actual time=0.030..83.026 rows=108037 loops=1)
        ->  Index Only Scan using idx_prodcats_cat_prod_id on prodcats c  (cost=0.43..0.54 rows=1 width=4) (actual time=0.001..0.001 rows=0 loops=108037)
              Index Cond: ((category_id = 248688) AND (product_id = p.id))
              Heap Fetches: 0
Planning time: 0.585 ms
Execution time: 264.664 ms

Questo è in effetti abbastanza logico poiché l'indice B-tree qui non produce risultati diretti, è usato solo come guida per la scansione sequenziale.

Confrontiamo con la query GIN:

SELECT * FROM products WHERE id in (
  SELECT id FROM products WHERE category_ids @> ARRAY[248688]
  ORDER BY score DESC, title LIMIT 10 OFFSET 300
) ORDER BY score DESC, title;

Sort  (cost=2519.53..2519.55 rows=10 width=1390) (actual time=143.809..143.809 rows=10 loops=1)
  Sort Key: products.score, products.title
  Sort Method: quicksort  Memory: 35kB
  ->  Nested Loop  (cost=2435.14..2519.36 rows=10 width=1390) (actual time=143.693..143.736 rows=10 loops=1)
        ->  HashAggregate  (cost=2434.71..2434.81 rows=10 width=4) (actual time=143.678..143.680 rows=10 loops=1)
              Group Key: products_1.id
              ->  Limit  (cost=2434.56..2434.59 rows=10 width=72) (actual time=143.668..143.670 rows=10 loops=1)
                    ->  Sort  (cost=2433.81..2435.43 rows=646 width=72) (actual time=143.642..143.653 rows=310 loops=1)
                          Sort Key: products_1.score, products_1.title
                          Sort Method: top-N heapsort  Memory: 68kB
                          ->  Bitmap Heap Scan on products products_1  (cost=17.01..2403.85 rows=646 width=72) (actual time=11.625..31.868 rows=41666 loops=1)
                                Recheck Cond: (category_ids @> '{248688}'::integer[])
                                Heap Blocks: exact=6471
                                ->  Bitmap Index Scan on idx_products_category_ids_gin  (cost=0.00..16.85 rows=646 width=0) (actual time=9.916..9.916 rows=41666 loops=1)
                                      Index Cond: (category_ids @> '{248688}'::integer[])
        ->  Index Scan using products_pkey on products  (cost=0.42..8.45 rows=1 width=1390) (actual time=0.004..0.004 rows=1 loops=10)
              Index Cond: (id = products_1.id)
Planning time: 0.630 ms
Execution time: 143.921 ms

Il risultato di GIN è molto meglio. Ho controllato con varie combinazioni di numero di prodotti e offset, in nessun caso l'approccio della tabella di giunzione era migliore .

Il potere dell'indice reale

Affinché PostgreSQL utilizzi completamente l'indice per l'ordinamento, tutti i WHEREparametri di query e i ORDER BYparametri devono risiedere in un singolo indice B-tree. Per fare ciò ho copiato i campi di ordinamento dal prodotto alla tabella di giunzione:

CREATE TABLE prodcats AS SELECT id AS product_id, unnest(category_ids) AS category_id, score, title FROM products;
CREATE INDEX idx_prodcats_1 ON prodcats (category_id, score DESC, title, product_id);

SELECT * FROM products WHERE id in (SELECT product_id FROM prodcats WHERE category_id=248688 ORDER BY score DESC, title LIMIT 10 OFFSET 30000) ORDER BY score DESC, title;

Sort  (cost=2149.65..2149.67 rows=10 width=1390) (actual time=7.011..7.011 rows=10 loops=1)
  Sort Key: products.score, products.title
  Sort Method: quicksort  Memory: 35kB
  ->  Nested Loop  (cost=2065.26..2149.48 rows=10 width=1390) (actual time=6.916..6.950 rows=10 loops=1)
        ->  HashAggregate  (cost=2064.83..2064.93 rows=10 width=4) (actual time=6.902..6.904 rows=10 loops=1)
              Group Key: prodcats.product_id
              ->  Limit  (cost=2064.02..2064.71 rows=10 width=74) (actual time=6.893..6.895 rows=10 loops=1)
                    ->  Index Only Scan using idx_prodcats_1 on prodcats  (cost=0.56..2860.10 rows=41574 width=74) (actual time=0.010..6.173 rows=30010 loops=1)
                          Index Cond: (category_id = 248688)
                          Heap Fetches: 0
        ->  Index Scan using products_pkey on products  (cost=0.42..8.45 rows=1 width=1390) (actual time=0.003..0.003 rows=1 loops=10)
              Index Cond: (id = prodcats.product_id)
Planning time: 0.318 ms
Execution time: 7.066 ms

E questo è lo scenario peggiore con un gran numero di prodotti nella categoria scelta e un grande offset. Quando offset = 300 il tempo di esecuzione è di soli 0,5 ms.

Sfortunatamente mantenere una tabella di giunzione del genere richiede uno sforzo extra. Potrebbe essere realizzato tramite viste materializzate indicizzate, ma ciò è utile solo quando i tuoi dati si aggiornano raramente, poiché l'aggiornamento di tale vista materializzata è un'operazione piuttosto pesante.

Quindi rimango con l'indice GIN finora, con work_memquery di footprint di memoria aumentata e ridotta.


Non è necessario riavviare per modificare l' work_memimpostazione generale in postgresql.conf. Ricarica è abbastanza. E lasciatemi mettere in guardia dall'impostazione work_memtroppo alta a livello globale in un ambiente multiutente (neanche troppo basso). Se hai delle domande che richiedono di più work_mem, impostale in modo più elevato per la sessione solo con SET- o solo la transazione con SET LOCAL. Vedi: dba.stackexchange.com/a/48633/3684
Erwin Brandstetter,

Che risposta eccezionale. Mi ha aiutato molto, in particolare con il disco -> operazione di ordinamento in memoria, cambio rapido per una grande vittoria, grazie!
Ricardo Villamil,

4

Ecco alcuni suggerimenti rapidi che possono aiutarti a migliorare le tue prestazioni. Inizierò con la punta più semplice, che è quasi senza sforzo da parte tua, e passerò alla punta più difficile dopo la prima.

1. work_mem

Quindi, vedo subito che un ordinamento riportato nel tuo piano esplicativo Sort Method: external merge Disk: 5696kBsta consumando meno di 6 MB, ma si sta riversando su disco. È necessario aumentare le work_memimpostazioni nel postgresql.conffile per essere sufficientemente grandi da consentire l'ordinamento nella memoria.

EDIT: Inoltre, a un'ulteriore ispezione, vedo che dopo aver utilizzato l'indice per verificare catgory_idsquale si adatta ai tuoi criteri, la scansione dell'indice bitmap è costretta a diventare "lossy" e deve ricontrollare la condizione durante la lettura delle righe all'interno delle relative pagine heap . Fare riferimento a questo post su postgresql.org per una spiegazione migliore di quella che ho fornito. : P Il punto principale è che il tuo work_memè troppo basso. Se non hai ottimizzato le impostazioni predefinite sul tuo server, non funzionerà bene.

Questa correzione non ti richiederà sostanzialmente tempo. Un cambio a postgresql.confe il gioco è fatto! Fare riferimento a questa pagina di ottimizzazione delle prestazioni per ulteriori suggerimenti.

2. Cambio di schema

Quindi, hai preso la decisione nella progettazione dello schema di denormalizzare category_idsin un array intero, che ti costringe quindi a utilizzare un indice GIN o GIST per ottenere un accesso rapido. Nella mia esperienza, la scelta di un indice GIN sarà più veloce per le letture rispetto a un GIST, quindi in quel caso hai fatto la scelta giusta. Tuttavia, GIN è un indice non ordinato; pensare più come un valore-chiave, dove predicati parità sono facili da controllare, ma operazioni come WHERE >, WHERE <o ORDER BYnon siano facilitate dall'indice.

Un approccio decente sarebbe quello di normalizzare la progettazione utilizzando una tabella bridge / tabella di giunzione , utilizzata per specificare relazioni molti-a-molti nei database.

In questo caso, hai molte categorie e un set di numeri interi corrispondenti category_ide hai molti prodotti e i loro corrispondenti product_ids. Invece di una colonna nella tabella del prodotto che è un array intero di category_ids, rimuovi questa colonna di array dal tuo schema e crea una tabella come

CREATE TABLE join_products_categories (product_id int, category_id int);

Quindi, puoi generare indici B-tree sulle due colonne della tabella bridge,

CREATE INDEX idx_products_in_join_table ON join_products_categories (product_id);
CREATE INDEX idx_products_in_join_table ON join_products_categories (category_id);

Solo la mia modesta opinione, ma questi cambiamenti possono fare una grande differenza per te. Prova quel work_memcambiamento per prima cosa, almeno.

Buona fortuna!

MODIFICARE:

Crea un indice aggiuntivo per facilitare l'ordinamento

Pertanto, se nel tempo la tua linea di prodotti si espande, alcune query potrebbero restituire molti risultati (migliaia, decine di migliaia?), Ma che potrebbero essere solo un piccolo sottoinsieme della tua linea di prodotti totale. In questi casi, l'ordinamento può anche essere piuttosto costoso se fatto in memoria, ma un indice progettato in modo appropriato può essere utilizzato per aiutare l'ordinamento.

Vedi la documentazione ufficiale di PostgreSQL che descrive gli indici e ORDER BY .

Se si crea un indice corrispondente ai propri ORDER BYrequisiti

CREATE INDEX idx_product_sort ON products (score DESC, title);

Postgres ottimizzerà e deciderà se utilizzare l'indice o eseguire un ordinamento esplicito sarà più conveniente. Tieni presente che non esiste alcuna garanzia che Postgres utilizzerà l'indice; cercherà di ottimizzare le prestazioni e scegliere tra l'utilizzo dell'indice o l'ordinamento esplicito. Se crei questo indice, monitoralo per vedere se viene usato abbastanza per giustificarne la creazione e rilascialo se la maggior parte dei tuoi tipi viene eseguita in modo esplicito.

Tuttavia, a questo punto, il tuo imporvement "big bang for the buck" probabilmente ne utilizzerà di più work_mem, ma ci sono casi in cui l'indice potrebbe supportare l'ordinamento.


Stavo anche pensando di utilizzare la tabella di giunzione per evitare GIN. Ma non hai specificato come questo aiuterà con l'ordinamento. Penso che non aiuterà. Ho provato a unire la tabella dei prodotti con un set di ID prodotto raccolti tramite query GIN, che credo sia abbastanza simile al join che stai offrendo e che l'operazione non ha potuto utilizzare l'indice b-tree su punteggio e titolo. Forse ho creato un indice sbagliato. Potresti per favore approfondire questo.
Yaroslav Stavnichiy,

Mi scuso, forse non ho spiegato abbastanza chiaramente. L'alterazione della work_memconfigurazione è stata intesa come una soluzione al problema "ordinamento su disco", nonché al problema di ricontrollo delle condizioni. Con l'aumentare del numero di prodotti, potrebbe essere necessario disporre di un indice aggiuntivo per ordinare. Si prega di consultare le mie modifiche sopra per chiarimenti.
Chris,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.