SlideShare une entreprise Scribd logo
1  sur  25
Télécharger pour lire hors ligne
1/25
Tri & PostgreSQL
Estimer la mémoire nécessaire pour un tri
Julien Rouhaud
Meetup Nantes #11
4 octobre 2018
Julien Rouhaud Tri & PostgreSQL
2/25
Quel problème ?
rjuju=# d t1
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id1 | integer | | |
id2 | bigint | | |
id3 | integer | | |
rjuju=# SET work_mem = '800kB';
rjuju=# EXPLAIN ANALYZE SELECT id1, id2, id3
FROM t1 ORDER BY id1;
QUERY PLAN
---------------------------------------------------------------------
Sort (rows=10000 width=16) (actual rows=10000)
Sort Key: id1
Sort Method: external merge Disk: 296kB
-> Seq Scan on t1 (rows=10000 width=16) (actual rows=10000)
Julien Rouhaud Tri & PostgreSQL
3/25
Au doigt mouillé
Combien de work_mem ?
Optimiser la requête ?
Julien Rouhaud Tri & PostgreSQL
4/25
Quel problème ?
rjuju=# EXPLAIN ANALYZE SELECT id2, id1, id3
FROM t1 ORDER BY id1;
QUERY PLAN
---------------------------------------------------------------------
Sort (rows=10000 width=16) (actual rows=10000)
Sort Key: id1
Sort Method: quicksort Memory: 787kB
-> Seq Scan on t1 (rows=10000 width=16) (actual rows=10000)
Julien Rouhaud Tri & PostgreSQL
5/25
Quicksort
Algorithme de tri classique
Tri "en place"
Implémenté dans src/backend/utils/sort/tuplesort.c
Se fera en mémoire s’il peut stocker toutes les
lignes à trier en mémoire
Julien Rouhaud Tri & PostgreSQL
6/25
top-N heapsort
Autre implémentation de tri en mémoire
ORDER BY X LIMIT Y
Utilisé automatiquement si
On a déjà stocké au moins Y lignes, et que le
work_mem est épuisé
On a déjà stocké au moins Y * 2 lignes
Peut largement dépasser le work_mem !
Julien Rouhaud Tri & PostgreSQL
7/25
Allocation mémoire
Généralités
Postgres est écrit en C, pas de GC ni de destructeur
À la place, des contextes mémoires
Plusieurs implémentation, généralement AllocSet
palloc() / pfree()
Julien Rouhaud Tri & PostgreSQL
8/25
Allocation mémoire
Utilisation courante de la mémoire pour le tri
Un variable maintient la quantité de mémoire
utilisée
Deux macro pour mettre à jour cette quantité
(spécifique tuplesort)
Une fonction de l’allocateur mémoire pour savoir la
quantité de mémoire vraiment utilisée
#define USEMEM(state,amt) ((state)->availMem -= (amt))
#define FREEMEM(state,amt) ((state)->availMem += (amt))
state->gros_tableau = palloc(taille);
USEMEM(state, GetMemoryChunkSpace(state->gros_tableau));
Julien Rouhaud Tri & PostgreSQL
9/25
AllocSet
Généralités
Alloue des "chunks"
Par puissance de 2, entre 8B et 8192B
Au delà, chunk dédié à la bonne taille
Overhead fixe du header : 16B
Julien Rouhaud Tri & PostgreSQL
10/25
AllocSet
Un peu d’implémentation
Implémenté dans src/backend/utils/mmgr/aset.c
typedef struct AllocChunkData {
Size size;
void *aset;
} AllocChunkData;
#define ALLOC_CHUNKHDRSZ sizeof(struct AllocChunkData)
static Size
AllocSetGetChunkSpace(MemoryContext context, void *pointer) {
AllocChunk chunk = AllocPointerGetChunk(pointer);
Size result;
result = chunk->size + ALLOC_CHUNKHDRSZ;
return result;
}
taille contexte associé Les données
Julien Rouhaud Tri & PostgreSQL
11/25
Stockage des données à trier
1 - tableau contenant les lignes
1. Un gros tableau, contenant les pointeurs des
lignes à trier
Ces pointeurs sont stockés dans une struct :
SortTuple (taille : 24B)
typedef struct {
void *tuple; /* the tuple itself */
Datum datum1; /* value of first key column */
bool isnull1; /* is first key column NULL? */
int tupindex; /* see notes above */
} SortTuple;
Naivement, on devrait avoir besoin de
(nb_ligne * sizeof(SortTuple)) + ALLOC_CHUNKHDRSZ
(nb_ligne * 24B) + 16B
Sauf que...
Julien Rouhaud Tri & PostgreSQL
12/25
Stockage des données à trier
1 - tableau contenant les lignes
PostgreSQL alloue par défaut de quoi stocker 1024
lignes
struct Tuplesortstate {
[...]
/* This array holds the tuples now in sort memory... */
SortTuple *memtuples; /* array of SortTuple structs */
int memtupcount; /* number of tuples currently present */
int memtupsize; /* allocated length of memtuples array */
[...]
}
state->memtupcount = 0;
state->memtupsize = 1024;
state->memtuples = palloc(state->memtupsize * sizeof(SortTuple));
[...]
Julien Rouhaud Tri & PostgreSQL
13/25
Stockage des données à trier
1 - tableau contenant les lignes
Et croît en doublant la capacité, avec une limite
/*
* Grow the memtuples[] array, if possible within our memory
* constraint. We must not exceed INT_MAX tuples in memory or
* the caller-provided.memory limit. [...]
* Normally, at each increment we double the size of the array.
* [...]
*/
static bool grow_memtuples(Tuplesortstate *state)
INT_MAX (2147483647), ~2.1 milliards d’entrées,
~48GB
Minimum de (1024 * 24B) + 16B, environ 24kB
Nombre de lignes arrondi à la puissance de 2
supérieure
ex pour 10000 lignes : (16384 * 24B) + 16B,
environ 384kB
Julien Rouhaud Tri & PostgreSQL
14/25
Stockage des données à trier
2 - ajout des lignes à trier
2. Chaque ligne est allouée séparément, puis
stockée dans le tableau
on stock des MinimalTuple, une version épurée
d’une ligne sans les information de visibilité
struct MinimalTupleData
{
uint32 t_len; /* actual length of minimal tuple */
char mt_padding[MINIMAL_TUPLE_PADDING];
/* Fields below here must match HeapTupleHeaderData! */
uint16 t_infomask2; /* number of attributes + various flags */
uint16 t_infomask; /* various flag bits, see below */
uint8 t_hoff; /* sizeof header incl. bitmap, padding */
bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */
/* MORE DATA FOLLOWS AT END OF STRUCT */
};
typedef MinimalTupleData *MinimalTuple;
Julien Rouhaud Tri & PostgreSQL
15/25
Stockage des données à trier
2 - ajout des lignes à trier
On ne stocke pas une ligne entière d’une table
Mais la TargetList (clause SELECT) d’une relation à
trier (table, résultat d’une jointure)
Les règles de stockage d’une ligne s’appliquent
Julien Rouhaud Tri & PostgreSQL
16/25
Stockage d’un MinimalTuple
Généralités
Un header fixe de 15B aligné, 16B
Un bitmapset de NULL si au moins une colonne est
nulle
Un champ Oid si la table a été créée avec WITH
OIDS (la plupart des catalogues)
Les colonnes non NULL, avec leurs règles
d’alignement
Le tout arrondi à la puissance de 2 supérieure (si
moins de 8kB)
et 16B d’overhead, la ligne étant allouée dans un
chunk
Julien Rouhaud Tri & PostgreSQL
17/25
Stockage d’un MinimalTuple
Stockage des NULL
bitmapset présent si au moins une colonne de la
ligne est NULL
Un bitmapset, 1 bit par colonne, arrondi à l’octet
supérieur
* BITMAPLEN(NATTS) -
* Computes size of null bitmap given number of data columns.
*/
#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
MinimalTuple
heap_form_minimal_tuple(TupleDesc tupleDescriptor,
Datum *values,
bool *isnull)
{
int numberOfAttributes = tupleDescriptor->natts;
[...]
if (hasnull)
len += BITMAPLEN(numberOfAttributes);
Julien Rouhaud Tri & PostgreSQL
18/25
Stockage d’un MinimalTuple
Stockage des attributs
Règles d’alignement des types standard
rjuju=# SELECT attname, attlen, attalign
FROM pg_class c JOIN pg_attribute a on a.attrelid = c.oid
WHERE c.relname = 't1' AND a.attnum > 0 ORDER BY attnum;
attname | attlen | attalign
---------+--------+----------
id1 | 4 | i
id2 | 8 | d
id3 | 4 | i
catalog-pg-type.html
c = char alignment, i.e., no alignment needed.
s = short alignment (2 bytes on most machines).
i = int alignment (4 bytes on most machines).
d = double alignment (8 bytes on many machines,
but by no means all).
Julien Rouhaud Tri & PostgreSQL
19/25
Stockage d’un MinimalTuple
Stockage des attributs
Ordre de colonne non optimal
SELECT id1, id2, id3 FROM t1 ORDER BY id;
id1 ---- id2 id3
16B de données, 4B perdus, 20B
total ligne : 16B (header) + 20B = 36B, arrondi à
64B
total alloué : 64B + 16B (overhead palloc) = 80B
Ordre de colonne optimal
SELECT id2, id1, id3 FROM t1 ORDER BY id;
id2 id1id1id1id1id1id1id1id1 id3
16B de données, pas d’espace perdu
total ligne : 16B (header) + 16B = 32B, arrondi à
32B
total alloué : 32B + 16B (overhead palloc) = 48B
Julien Rouhaud Tri & PostgreSQL
20/25
Mémoire totale
Soit N1 le nombre de lignes
Soit N2 le nombre de lignes, arrondi à la puissance de 2 supérieure,
minimum 1024
1 - Espace pour le tableau :
(N2 ∗ 24) + 16
Soit L1 la taille moyenne d’une ligne *
L1 =
nbAtt
attnum=1
attlen(attnum)
Soit L2 la taille totale allouée, arrondi à la puissance de 2
supérieure :
L2 = L1 + 16
2 - Espace pour les lignes :
(L2 + 16) ∗ N1
* Case simple : pas de NULL ni OID, < 8kB, sans tenir compte de
l’alignement, types de taille fixe
Julien Rouhaud Tri & PostgreSQL
21/25
pg_sortstats
extension pour instrumenter les tris
github.com/powa-team/pg_sortstats
estimation du work_mem requis, type de tris,
mémoire utilisée...
compteurs cumulés
aggrégé par (querid, dbid, userid, sort_key)
fonctionelle, mais perfectible (NULL pas pris en
compte, ...)
Julien Rouhaud Tri & PostgreSQL
22/25
pg_sortstats
Métriques retournées
lines nombre totale de lignes en entrée du tri
lines_to_sort nombre de lignes à trier réellement
work_mems work_mem estimé pour trier en mémoire
topn_sorts nombre de tri effectué avec un top-N heapsort
quicksorts nombre de tri effectué avec un quicksort
external_sorts nombre de tri effectué avec un external sort
external_merges nombre de tri effectué avec un external merge
nbtapes nombre de tapes utilisés pour les external merge
space_disk espace disque utilisé
space_memory espace mémoire utilisé
non_parallels nombre de tri non parallèles
nb_workers nombre de workers total utilisés (si parallèle)
Julien Rouhaud Tri & PostgreSQL
23/25
pg_sortstats
Idées d’utilisation
avoir une idée du nombre de tris dans son
application
détecter des index manquants pour satisfaire les
tris
aider à configurer le work_mem
capturer régulièrement la sortie (avec PoWA par
exemple), et
avoir une idée du work_mem nécessaire pour
satisfaire 80% des tris entre 9h et 18h
combien de tris passeraient en RAM si on
augmentait le work_mem de 10%
. . .
log_temp_files & pgBadger restent indispensables !
Julien Rouhaud Tri & PostgreSQL
24/25
pg_sortstats
Et la suite ?
ajouter le support pour les Hash et HashAgg
stocker le work_mem effectif ?
meilleure représentation des données ?
autre ?
Julien Rouhaud Tri & PostgreSQL
25/25
Questions ?
rjuju.github.io
@rjuju123
Julien Rouhaud Tri & PostgreSQL

Contenu connexe

Tendances

FLTauR - Construction de modèles de prévision sous r avec le package caret
FLTauR - Construction de modèles de prévision sous r avec le package caretFLTauR - Construction de modèles de prévision sous r avec le package caret
FLTauR - Construction de modèles de prévision sous r avec le package caretjfeudeline
 
Bases de données image : structuration de l'espace des descripteurs et recher...
Bases de données image : structuration de l'espace des descripteurs et recher...Bases de données image : structuration de l'espace des descripteurs et recher...
Bases de données image : structuration de l'espace des descripteurs et recher...Guillaume MOCQUET
 
Programmation fonctionnelle
Programmation fonctionnelleProgrammation fonctionnelle
Programmation fonctionnelleGeeks Anonymes
 
Benharratharijtp2 classification
Benharratharijtp2 classificationBenharratharijtp2 classification
Benharratharijtp2 classificationARIJ BenHarrath
 
Ben harrath arijtp3 les règles d'association
Ben harrath arijtp3 les règles d'association Ben harrath arijtp3 les règles d'association
Ben harrath arijtp3 les règles d'association ARIJ BenHarrath
 
BigData_TP5 : Neo4J
BigData_TP5 : Neo4JBigData_TP5 : Neo4J
BigData_TP5 : Neo4JLilia Sfaxi
 
Chap7 simulation numérique
Chap7 simulation numériqueChap7 simulation numérique
Chap7 simulation numériqueMariem ZAOUALI
 
Développement informatique : Chaines de caractères et expressions regulières
Développement informatique : Chaines de caractères et expressions regulièresDéveloppement informatique : Chaines de caractères et expressions regulières
Développement informatique : Chaines de caractères et expressions regulièresECAM Brussels Engineering School
 

Tendances (18)

Dijkstra kshortest
Dijkstra kshortestDijkstra kshortest
Dijkstra kshortest
 
FLTauR - Construction de modèles de prévision sous r avec le package caret
FLTauR - Construction de modèles de prévision sous r avec le package caretFLTauR - Construction de modèles de prévision sous r avec le package caret
FLTauR - Construction de modèles de prévision sous r avec le package caret
 
Paug renderscript-mars-2013
Paug renderscript-mars-2013Paug renderscript-mars-2013
Paug renderscript-mars-2013
 
Python avancé : Tuple et objet
Python avancé : Tuple et objetPython avancé : Tuple et objet
Python avancé : Tuple et objet
 
Mathématiques et Python
Mathématiques et PythonMathématiques et Python
Mathématiques et Python
 
Python profiling
Python profilingPython profiling
Python profiling
 
Bases de données image : structuration de l'espace des descripteurs et recher...
Bases de données image : structuration de l'espace des descripteurs et recher...Bases de données image : structuration de l'espace des descripteurs et recher...
Bases de données image : structuration de l'espace des descripteurs et recher...
 
Programmation fonctionnelle
Programmation fonctionnelleProgrammation fonctionnelle
Programmation fonctionnelle
 
cours de Matlab
 cours de Matlab cours de Matlab
cours de Matlab
 
Benharratharijtp2 classification
Benharratharijtp2 classificationBenharratharijtp2 classification
Benharratharijtp2 classification
 
Tcl gdal
Tcl gdalTcl gdal
Tcl gdal
 
Chapitre2 2
Chapitre2 2Chapitre2 2
Chapitre2 2
 
Ben harrath arijtp3 les règles d'association
Ben harrath arijtp3 les règles d'association Ben harrath arijtp3 les règles d'association
Ben harrath arijtp3 les règles d'association
 
Programmation Fonctionnelle
Programmation FonctionnelleProgrammation Fonctionnelle
Programmation Fonctionnelle
 
Theme 7
Theme 7Theme 7
Theme 7
 
BigData_TP5 : Neo4J
BigData_TP5 : Neo4JBigData_TP5 : Neo4J
BigData_TP5 : Neo4J
 
Chap7 simulation numérique
Chap7 simulation numériqueChap7 simulation numérique
Chap7 simulation numérique
 
Développement informatique : Chaines de caractères et expressions regulières
Développement informatique : Chaines de caractères et expressions regulièresDéveloppement informatique : Chaines de caractères et expressions regulières
Développement informatique : Chaines de caractères et expressions regulières
 

Similaire à 2018-10-04 Meetup PG Nantes - PostgreSQL: Estimer la mémoire nécessaire pour un tri

OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...
OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...
OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...Pôle Systematic Paris-Region
 
ALT.NET Modéliser Parallèle avec C# 4.0
ALT.NET Modéliser Parallèle avec C# 4.0ALT.NET Modéliser Parallèle avec C# 4.0
ALT.NET Modéliser Parallèle avec C# 4.0Bruno Boucard
 
MapReduce au Niveau RP*
MapReduce au Niveau RP*MapReduce au Niveau RP*
MapReduce au Niveau RP*UHBC
 
Oracle : extension du langage SQL
Oracle : extension du langage SQLOracle : extension du langage SQL
Oracle : extension du langage SQLMohammed Jaafar
 
Interception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelInterception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelThierry Gayet
 
Cours python avancé
Cours python avancéCours python avancé
Cours python avancépierrepo
 
CHAPITRE3_Fondements_Big_Data_MR_YARN - converted (1).pdf
CHAPITRE3_Fondements_Big_Data_MR_YARN - converted (1).pdfCHAPITRE3_Fondements_Big_Data_MR_YARN - converted (1).pdf
CHAPITRE3_Fondements_Big_Data_MR_YARN - converted (1).pdfYounesOuladSayad1
 
Cours Systemes embarques.pptx
Cours Systemes embarques.pptxCours Systemes embarques.pptx
Cours Systemes embarques.pptxSihemNasri3
 
Digital_Signal_Processors_TG_FULL.pdf
Digital_Signal_Processors_TG_FULL.pdfDigital_Signal_Processors_TG_FULL.pdf
Digital_Signal_Processors_TG_FULL.pdfHouBou3
 
Fonctions Mono-Ligne
Fonctions Mono-LigneFonctions Mono-Ligne
Fonctions Mono-Lignewebreaker
 
Tpdba1
Tpdba1Tpdba1
Tpdba1infcom
 
Cours algorithmique et complexite complet
Cours algorithmique et complexite completCours algorithmique et complexite complet
Cours algorithmique et complexite completChahrawoods Dmz
 
Cours algorithmique et complexite
Cours algorithmique et complexite Cours algorithmique et complexite
Cours algorithmique et complexite Saddem Chikh
 
Cours algorithmique et complexite complet
Cours algorithmique et complexite completCours algorithmique et complexite complet
Cours algorithmique et complexite completChahrawoods Dmz
 
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...Normandy JUG
 

Similaire à 2018-10-04 Meetup PG Nantes - PostgreSQL: Estimer la mémoire nécessaire pour un tri (20)

OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...
OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...
OSIS18_IoT: L'approche machine virtuelle pour les microcontrôleurs, le projet...
 
ALT.NET Modéliser Parallèle avec C# 4.0
ALT.NET Modéliser Parallèle avec C# 4.0ALT.NET Modéliser Parallèle avec C# 4.0
ALT.NET Modéliser Parallèle avec C# 4.0
 
MapReduce au Niveau RP*
MapReduce au Niveau RP*MapReduce au Niveau RP*
MapReduce au Niveau RP*
 
Approximation de ritter
Approximation de ritterApproximation de ritter
Approximation de ritter
 
Oracle : extension du langage SQL
Oracle : extension du langage SQLOracle : extension du langage SQL
Oracle : extension du langage SQL
 
algo-imsi-2.pdf
algo-imsi-2.pdfalgo-imsi-2.pdf
algo-imsi-2.pdf
 
Interception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appelInterception de signal avec dump de la pile d'appel
Interception de signal avec dump de la pile d'appel
 
Cours python avancé
Cours python avancéCours python avancé
Cours python avancé
 
prog_reg.pptx
prog_reg.pptxprog_reg.pptx
prog_reg.pptx
 
CHAPITRE3_Fondements_Big_Data_MR_YARN - converted (1).pdf
CHAPITRE3_Fondements_Big_Data_MR_YARN - converted (1).pdfCHAPITRE3_Fondements_Big_Data_MR_YARN - converted (1).pdf
CHAPITRE3_Fondements_Big_Data_MR_YARN - converted (1).pdf
 
Boost.SIMD
Boost.SIMDBoost.SIMD
Boost.SIMD
 
Cours Systemes embarques.pptx
Cours Systemes embarques.pptxCours Systemes embarques.pptx
Cours Systemes embarques.pptx
 
Digital_Signal_Processors_TG_FULL.pdf
Digital_Signal_Processors_TG_FULL.pdfDigital_Signal_Processors_TG_FULL.pdf
Digital_Signal_Processors_TG_FULL.pdf
 
Fonctions Mono-Ligne
Fonctions Mono-LigneFonctions Mono-Ligne
Fonctions Mono-Ligne
 
Tpdba1
Tpdba1Tpdba1
Tpdba1
 
Cours algorithmique et complexite complet
Cours algorithmique et complexite completCours algorithmique et complexite complet
Cours algorithmique et complexite complet
 
Cours algorithmique et complexite
Cours algorithmique et complexite Cours algorithmique et complexite
Cours algorithmique et complexite
 
Cours algorithmique et complexite complet
Cours algorithmique et complexite completCours algorithmique et complexite complet
Cours algorithmique et complexite complet
 
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
 
Chapitre 1 rappel
Chapitre 1   rappelChapitre 1   rappel
Chapitre 1 rappel
 

2018-10-04 Meetup PG Nantes - PostgreSQL: Estimer la mémoire nécessaire pour un tri

  • 1. 1/25 Tri & PostgreSQL Estimer la mémoire nécessaire pour un tri Julien Rouhaud Meetup Nantes #11 4 octobre 2018 Julien Rouhaud Tri & PostgreSQL
  • 2. 2/25 Quel problème ? rjuju=# d t1 Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+--------- id1 | integer | | | id2 | bigint | | | id3 | integer | | | rjuju=# SET work_mem = '800kB'; rjuju=# EXPLAIN ANALYZE SELECT id1, id2, id3 FROM t1 ORDER BY id1; QUERY PLAN --------------------------------------------------------------------- Sort (rows=10000 width=16) (actual rows=10000) Sort Key: id1 Sort Method: external merge Disk: 296kB -> Seq Scan on t1 (rows=10000 width=16) (actual rows=10000) Julien Rouhaud Tri & PostgreSQL
  • 3. 3/25 Au doigt mouillé Combien de work_mem ? Optimiser la requête ? Julien Rouhaud Tri & PostgreSQL
  • 4. 4/25 Quel problème ? rjuju=# EXPLAIN ANALYZE SELECT id2, id1, id3 FROM t1 ORDER BY id1; QUERY PLAN --------------------------------------------------------------------- Sort (rows=10000 width=16) (actual rows=10000) Sort Key: id1 Sort Method: quicksort Memory: 787kB -> Seq Scan on t1 (rows=10000 width=16) (actual rows=10000) Julien Rouhaud Tri & PostgreSQL
  • 5. 5/25 Quicksort Algorithme de tri classique Tri "en place" Implémenté dans src/backend/utils/sort/tuplesort.c Se fera en mémoire s’il peut stocker toutes les lignes à trier en mémoire Julien Rouhaud Tri & PostgreSQL
  • 6. 6/25 top-N heapsort Autre implémentation de tri en mémoire ORDER BY X LIMIT Y Utilisé automatiquement si On a déjà stocké au moins Y lignes, et que le work_mem est épuisé On a déjà stocké au moins Y * 2 lignes Peut largement dépasser le work_mem ! Julien Rouhaud Tri & PostgreSQL
  • 7. 7/25 Allocation mémoire Généralités Postgres est écrit en C, pas de GC ni de destructeur À la place, des contextes mémoires Plusieurs implémentation, généralement AllocSet palloc() / pfree() Julien Rouhaud Tri & PostgreSQL
  • 8. 8/25 Allocation mémoire Utilisation courante de la mémoire pour le tri Un variable maintient la quantité de mémoire utilisée Deux macro pour mettre à jour cette quantité (spécifique tuplesort) Une fonction de l’allocateur mémoire pour savoir la quantité de mémoire vraiment utilisée #define USEMEM(state,amt) ((state)->availMem -= (amt)) #define FREEMEM(state,amt) ((state)->availMem += (amt)) state->gros_tableau = palloc(taille); USEMEM(state, GetMemoryChunkSpace(state->gros_tableau)); Julien Rouhaud Tri & PostgreSQL
  • 9. 9/25 AllocSet Généralités Alloue des "chunks" Par puissance de 2, entre 8B et 8192B Au delà, chunk dédié à la bonne taille Overhead fixe du header : 16B Julien Rouhaud Tri & PostgreSQL
  • 10. 10/25 AllocSet Un peu d’implémentation Implémenté dans src/backend/utils/mmgr/aset.c typedef struct AllocChunkData { Size size; void *aset; } AllocChunkData; #define ALLOC_CHUNKHDRSZ sizeof(struct AllocChunkData) static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer) { AllocChunk chunk = AllocPointerGetChunk(pointer); Size result; result = chunk->size + ALLOC_CHUNKHDRSZ; return result; } taille contexte associé Les données Julien Rouhaud Tri & PostgreSQL
  • 11. 11/25 Stockage des données à trier 1 - tableau contenant les lignes 1. Un gros tableau, contenant les pointeurs des lignes à trier Ces pointeurs sont stockés dans une struct : SortTuple (taille : 24B) typedef struct { void *tuple; /* the tuple itself */ Datum datum1; /* value of first key column */ bool isnull1; /* is first key column NULL? */ int tupindex; /* see notes above */ } SortTuple; Naivement, on devrait avoir besoin de (nb_ligne * sizeof(SortTuple)) + ALLOC_CHUNKHDRSZ (nb_ligne * 24B) + 16B Sauf que... Julien Rouhaud Tri & PostgreSQL
  • 12. 12/25 Stockage des données à trier 1 - tableau contenant les lignes PostgreSQL alloue par défaut de quoi stocker 1024 lignes struct Tuplesortstate { [...] /* This array holds the tuples now in sort memory... */ SortTuple *memtuples; /* array of SortTuple structs */ int memtupcount; /* number of tuples currently present */ int memtupsize; /* allocated length of memtuples array */ [...] } state->memtupcount = 0; state->memtupsize = 1024; state->memtuples = palloc(state->memtupsize * sizeof(SortTuple)); [...] Julien Rouhaud Tri & PostgreSQL
  • 13. 13/25 Stockage des données à trier 1 - tableau contenant les lignes Et croît en doublant la capacité, avec une limite /* * Grow the memtuples[] array, if possible within our memory * constraint. We must not exceed INT_MAX tuples in memory or * the caller-provided.memory limit. [...] * Normally, at each increment we double the size of the array. * [...] */ static bool grow_memtuples(Tuplesortstate *state) INT_MAX (2147483647), ~2.1 milliards d’entrées, ~48GB Minimum de (1024 * 24B) + 16B, environ 24kB Nombre de lignes arrondi à la puissance de 2 supérieure ex pour 10000 lignes : (16384 * 24B) + 16B, environ 384kB Julien Rouhaud Tri & PostgreSQL
  • 14. 14/25 Stockage des données à trier 2 - ajout des lignes à trier 2. Chaque ligne est allouée séparément, puis stockée dans le tableau on stock des MinimalTuple, une version épurée d’une ligne sans les information de visibilité struct MinimalTupleData { uint32 t_len; /* actual length of minimal tuple */ char mt_padding[MINIMAL_TUPLE_PADDING]; /* Fields below here must match HeapTupleHeaderData! */ uint16 t_infomask2; /* number of attributes + various flags */ uint16 t_infomask; /* various flag bits, see below */ uint8 t_hoff; /* sizeof header incl. bitmap, padding */ bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]; /* bitmap of NULLs */ /* MORE DATA FOLLOWS AT END OF STRUCT */ }; typedef MinimalTupleData *MinimalTuple; Julien Rouhaud Tri & PostgreSQL
  • 15. 15/25 Stockage des données à trier 2 - ajout des lignes à trier On ne stocke pas une ligne entière d’une table Mais la TargetList (clause SELECT) d’une relation à trier (table, résultat d’une jointure) Les règles de stockage d’une ligne s’appliquent Julien Rouhaud Tri & PostgreSQL
  • 16. 16/25 Stockage d’un MinimalTuple Généralités Un header fixe de 15B aligné, 16B Un bitmapset de NULL si au moins une colonne est nulle Un champ Oid si la table a été créée avec WITH OIDS (la plupart des catalogues) Les colonnes non NULL, avec leurs règles d’alignement Le tout arrondi à la puissance de 2 supérieure (si moins de 8kB) et 16B d’overhead, la ligne étant allouée dans un chunk Julien Rouhaud Tri & PostgreSQL
  • 17. 17/25 Stockage d’un MinimalTuple Stockage des NULL bitmapset présent si au moins une colonne de la ligne est NULL Un bitmapset, 1 bit par colonne, arrondi à l’octet supérieur * BITMAPLEN(NATTS) - * Computes size of null bitmap given number of data columns. */ #define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8) MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull) { int numberOfAttributes = tupleDescriptor->natts; [...] if (hasnull) len += BITMAPLEN(numberOfAttributes); Julien Rouhaud Tri & PostgreSQL
  • 18. 18/25 Stockage d’un MinimalTuple Stockage des attributs Règles d’alignement des types standard rjuju=# SELECT attname, attlen, attalign FROM pg_class c JOIN pg_attribute a on a.attrelid = c.oid WHERE c.relname = 't1' AND a.attnum > 0 ORDER BY attnum; attname | attlen | attalign ---------+--------+---------- id1 | 4 | i id2 | 8 | d id3 | 4 | i catalog-pg-type.html c = char alignment, i.e., no alignment needed. s = short alignment (2 bytes on most machines). i = int alignment (4 bytes on most machines). d = double alignment (8 bytes on many machines, but by no means all). Julien Rouhaud Tri & PostgreSQL
  • 19. 19/25 Stockage d’un MinimalTuple Stockage des attributs Ordre de colonne non optimal SELECT id1, id2, id3 FROM t1 ORDER BY id; id1 ---- id2 id3 16B de données, 4B perdus, 20B total ligne : 16B (header) + 20B = 36B, arrondi à 64B total alloué : 64B + 16B (overhead palloc) = 80B Ordre de colonne optimal SELECT id2, id1, id3 FROM t1 ORDER BY id; id2 id1id1id1id1id1id1id1id1 id3 16B de données, pas d’espace perdu total ligne : 16B (header) + 16B = 32B, arrondi à 32B total alloué : 32B + 16B (overhead palloc) = 48B Julien Rouhaud Tri & PostgreSQL
  • 20. 20/25 Mémoire totale Soit N1 le nombre de lignes Soit N2 le nombre de lignes, arrondi à la puissance de 2 supérieure, minimum 1024 1 - Espace pour le tableau : (N2 ∗ 24) + 16 Soit L1 la taille moyenne d’une ligne * L1 = nbAtt attnum=1 attlen(attnum) Soit L2 la taille totale allouée, arrondi à la puissance de 2 supérieure : L2 = L1 + 16 2 - Espace pour les lignes : (L2 + 16) ∗ N1 * Case simple : pas de NULL ni OID, < 8kB, sans tenir compte de l’alignement, types de taille fixe Julien Rouhaud Tri & PostgreSQL
  • 21. 21/25 pg_sortstats extension pour instrumenter les tris github.com/powa-team/pg_sortstats estimation du work_mem requis, type de tris, mémoire utilisée... compteurs cumulés aggrégé par (querid, dbid, userid, sort_key) fonctionelle, mais perfectible (NULL pas pris en compte, ...) Julien Rouhaud Tri & PostgreSQL
  • 22. 22/25 pg_sortstats Métriques retournées lines nombre totale de lignes en entrée du tri lines_to_sort nombre de lignes à trier réellement work_mems work_mem estimé pour trier en mémoire topn_sorts nombre de tri effectué avec un top-N heapsort quicksorts nombre de tri effectué avec un quicksort external_sorts nombre de tri effectué avec un external sort external_merges nombre de tri effectué avec un external merge nbtapes nombre de tapes utilisés pour les external merge space_disk espace disque utilisé space_memory espace mémoire utilisé non_parallels nombre de tri non parallèles nb_workers nombre de workers total utilisés (si parallèle) Julien Rouhaud Tri & PostgreSQL
  • 23. 23/25 pg_sortstats Idées d’utilisation avoir une idée du nombre de tris dans son application détecter des index manquants pour satisfaire les tris aider à configurer le work_mem capturer régulièrement la sortie (avec PoWA par exemple), et avoir une idée du work_mem nécessaire pour satisfaire 80% des tris entre 9h et 18h combien de tris passeraient en RAM si on augmentait le work_mem de 10% . . . log_temp_files & pgBadger restent indispensables ! Julien Rouhaud Tri & PostgreSQL
  • 24. 24/25 pg_sortstats Et la suite ? ajouter le support pour les Hash et HashAgg stocker le work_mem effectif ? meilleure représentation des données ? autre ? Julien Rouhaud Tri & PostgreSQL