[OSM-dev-fr] "glonflement" des tables osm2pgsql...
Philippe Verdy
verdy_p at wanadoo.fr
Mar 12 Aou 16:38:13 UTC 2014
En terme d'I/O cela ne changera pas grand chose.
Même faire un UPDATE à la place d'un DELETE/INSERT n'aura pas grande
incidence tout bonnement car le premier DELETE aura déjà chargé les pages
qui seront les mêmes que celles affectées par l'INSERT qui suit pour mettre
à jour les index: elles sont encore en cache meˆme s'il y a un petit délai
entre les deux opérations et s'il y a beaucoup d'opérations concurrentes.
Même un UPDATE pourrait avoir poru effet de réorganiser des pages pour
maintenir le fill factor, car l'UPDATE peut changer la taille d'une ligne
de table (en plus ou en moins).
Si on veut être optimal toutefois, un simple SELECT n'a pour effet QUE de
charger les pages nécessaires dans le cache, ce qui rend ensuite l''INSERT
ou l'UPDATE qui suit quasi instantané (au moins pour les pages des index
qui sont utilisés pour faire le SELECT initial). Cependant le SELECT
initial peut se contenter souvent de ne lire qu'un seul index sans avoir à
mettre à jour toutes les tables et index liés, c'est donc plus rapide
puisque le volume de pages concerné est plus faible au cas où la clé n'est
pas trouvée et qu'on va finalement faire un INSERT. En revanche si le
SELECT initial trouve la clé, il est fort probable alors que toutes les
pages de toutes les tables et index liés seront affectées (mais là comme on
a trouvé la clé, et qu'on va faire un UPDATE en utilisant cette clé, les
pages de l'index utilisé pour fait le SELECT initial sont déjà en mémoire
et resteront lues uniquement, alors que les autres tables/index seront mis
à jour pendant l'UPDATE de la ligne trouvée).
Mais le problème de la méthode SELECT suivi de INSERT ou UDATE c'est la
concurrence d'accès: on doit utiliser le mode transactionnel et donc
"locker" les pages de l'index utilisé pour le SELECT initial. Et là ce sont
ces locks qui risquent d'entraver les performances.
Tout dépend donc de la granularité des transactions: qu'est-ce qui est
atomique dans l'opération INSERT ou UPDATE poru que cela ne provoque pas de
requêtes incohérentes dans les accès concurrents? Pour certaines opérations
de mises à jour comme celles-là où les accès concurrents sont majoritaires
on pourrait croire que DELETE+INSERT inconditionnel serait toujours
préférable, surtout s'il n'y a qu'un seul accès effectuant des mises à jour
des tables (et que tous les autres accès concurrents sont en lecture
seule). On ne peut pas réellement le garantir.
L'atomicité (transactionnelle) de l'opération DELETE+INSERT sera donc la
même que pour l'opération SELECT+(INSERT ou UPDATE) si on veut éviter des
requêtes incohérentes (et donc se retrouver plus tard avec des données
manquantes ou en trop qui restent oubliées dans la base ou éviter de se
retrouver avec des clés doubles (qui provoquent des erreurs
transactionnelels lors de l'INSERT dans une table à index unique).
Les bases utilisées ont de très nombreux accès concurrents; on ne peut pas
se passer réellement du mode transactionnel. De fait on a intérêt donc à
faire un "lock" tout au début des transactions avant de commencer les
modifs de la transaction, et donc cela milite effectivement pour des mises
à jour utilisant un SELECT initial pour ensuite faire selon qu'on a trouvé
on on la clé, un INSERT ou un UPDATE dans la même transaction (l'intérêt du
lock initial étant que l'opération de "rollback" ne fait que libérer les
"locks" et n'aura rien à modifier, il n'y aura eu donc en cas de conflit
nécessitant un rollback, aucun autre accès que des accès en lecture seule.
De plus les locks peuvent être obtenus tous ensembles de façon atomique, et
on eput utiliser alors le mode transactionnel "optimiste" (où les
"rollbacks" sont très peu probables, il n'y a qu'à libérer les locks en
cours pour éviter les deadlocks des accès concurrents, et le moteur peut
reprogrammer la transaction sans même avoir besoin de l'annuler ou la
signaler en erreur d'accès concurrent).
Dans tous les cas, le fill factor n'entre pas en jeu pour déterminer le
mode transactionnel. Ce qui compte ce sont uniquement les ratios entre I/O
en lecture seule et I/O en écriture pour les réorganisations de pages
d'index.
En revanche, le modèle de stockage des tables (le type de B-arbre utilisé)
joue un plus grand rôle: dans un B-arbre simple, on stocke les lignes de
table directement dans les pages de n'importe quel niveau (y compris poru
la page racine).
Cependant des modèles de stockage plus performants peuvent utiliser un
stockage différent pour les pages feuilles de l'arbre (stockant toutes les
colonnes de toutes les lignes) et pour les pages de branche ou de la racine
(ne stockant que les clés, lesquelles peuvent aussi être compressées en
utilisant le fait que leur tri cohérent induit une forte redondance entre
les clés voisines dans l'ordre de tri de l'index). Avec un tel modèle de
table, on peut stocker beaucoup de clés dans la même page, les
réorganisations sont très peu fréquentes par rapport aux pages feuilles
plus volumineuses.
Dans un tel modèle d'arbre ayant deux types de pages distincts, il est
possible de pousser un fill factor élevé pour les pages de branche ou
racines, tout en gardant un fill factor plus faible pour les pages
feuilles. Par exemple, un fill factor à 97% (où une mise à jour pourrait
nécessiter lors des réorganisations d'arbre, de traiter jusqu'à une
soixantaine de pages au pire, ou une trentaine en moyenne) pour les
branches ou la racine, et 85% (6 ou 7 pages au pire par réorganisation, ou
3 en moyenne) pour les pages feuilles contenant les colonnes clés et toutes
les autres colonnes de données. Ce modèle est d'autant plus intéressant que
la longueur moyenne des clés par ligne est beaucoup plus faible que la
longueur moyenne des lignes (incluant toutes les colonnes): quand la clé
est un simple entier 32 bits ou 64 bits (par exemple un ID d'objet OSM), il
sera à privilégier.
Choisir donc un modèle de table adapté optimisant la compression des clés
des pages branches/racine. Le modèle de B-arbre simple n'est pas optimal.
Là cela dépend du moteur SQL et des types de stockage de table/index qu'il
peut gérer (et de sa façon à compresser ou pas les clés).
Le 12 août 2014 17:30, Francescu GAROBY <f.garoby at gmail.com> a écrit :
> Je pensais plutôt à tester la présence (via un SELECT sur l'osm_id, qui
> doit être un champ indexé, je suppose...) et, selon la réponse, à faire un
> INSERT ou un UPDATE.
> Si un SELECT est sensiblement aussi rapide qu'un DELETE, et un INSERT
> aussi rapide qu'un UPDATE, tu ne verras pas de différence notable sur le
> temps de traitement, mais tu auras résolu ton problème de trous de partout.
>
> Francescu,
> (qui est développeur, pas DBA)
>
>
> Le 12 août 2014 17:11, Christian Quest <cquest at openstreetmap.fr> a écrit :
>
> A voir pourquoi ça a été codé comme ça dans osm2pgsql... il y a peut être
>> une bonne raison.
>>
>> Celle que je vois est liée à l'absence de commande REPLACE comme on la
>> trouve dans MySQL.
>> Du coup, il faudrait différencier les créations des mises à jour, ce qui
>> aurait un effet de bord important si on rejoue des diffs dans le désordre
>> ou alors compliquer sérieusement chaque UPDATE pour le doubler par un
>> INSERT en cas d'échec, mais ça peut valoir le coup.
>>
>> Pour le fillfactor, Philippe a grosso-modo couvert le sujet.
>>
>> Dans le cas des données OSM, on a une part de mise à jour somme toute
>> faible par rapport au volume global de la base et surtout pas mal d'ajouts.
>> On peut rester sur des fillfactor élevés pour données et index qui ont un
>> impact potentiellement négatif sur les mises à jour, mais très positif sur
>> les lectures. Pour une base osm2pgsql servant à générer beaucoup de tuiles,
>> les lectures sont très majoritaires.
>> L'autre aspect important est qu'en ayant des pages très remplies
>> (fillfactor élevé), on en a moins globalement et donc à quantité de RAM
>> égale on peut avoir une proportion plus importante de données en cache...
>> toujours plus rapide que des IO sur un SSD et à fortiori des IO sur HDD !
>>
>>
>>
>> Le 12 août 2014 13:47, Francescu GAROBY <f.garoby at gmail.com> a écrit :
>>
>>> Et ça ne vaudrait pas le coup de modifier la fonction
>>> "pgsql_modify_node" que tu pointes pour lui faire faire un UPDATE, plutôt
>>> qu'un INSERT/DELETE ? La modification ne me paraît pas compliquée et si ça
>>> peut faciliter votre histoire de fillfactor (j'avoue ne pas comprendre de
>>> quoi il s'agit)...
>>>
>>> Francescu
>>>
>>>
>>> Le 12 août 2014 12:47, Christian Quest <cquest at openstreetmap.fr> a
>>> écrit :
>>>
>>> Par défaut le fillfactor sur les data est de 100%, d'où l'idée de le
>>>> baisser un peu... mais l'efficacité dépendra aussi de comment osm2pgsql met
>>>> à jour les données et vu le code ça semble malheureusement se faire à coup
>>>> de DELETE/INSERT et pas d'UPDATE...
>>>> https://github.com/openstreetmap/osm2pgsql/blob/master/output-pgsql.c#L1432
>>>>
>>>> Je ne suis pas sûr dans ces conditions que ça serve à grand chose.
>>>>
>>>>
>>>> Le 12 août 2014 11:37, Christophe Merlet <redfox at redfoxcenter.org> a
>>>> écrit :
>>>>
>>>> Le 12/08/2014 10:10, Christian Quest a écrit :
>>>>> > Vu qu'on a 2 bases osm2pgsql monde à la structure identique sur les
>>>>> > serveurs tile et layers, j'ai comparé l'espace occupé par les tables
>>>>> car
>>>>> > celui-ci est compté actuellement sur nos SSD de 480 (tile) et 512Go
>>>>> > (layers).
>>>>> >
>>>>> > Il y a des différentes plus ou moins importantes. La plus étonnante
>>>>> > concerne planet_osm_line qui pour les seules data fait 55Go sur tile
>>>>> et
>>>>> > 39Go sur layers, soit une différence de 40%.
>>>>> >
>>>>> > Je m'explique difficilement ces différences.
>>>>> >
>>>>> > Je viens de recopier la table (CREATE TABLE line as SELECT * FROM
>>>>> > planet_osm_line) et j'ai une table de 35Go. Il y a donc des trous
>>>>> dans
>>>>> > les data ou alors c'est un auto-vacuum en cours qui provoque ce
>>>>> > gonflement alors que je pensais qu'il prenait des données en fin de
>>>>> > fichier pour les remettre dans les trous.
>>>>> >
>>>>> > Des idées de votre côté ?
>>>>>
>>>>>
>>>>> L'auto vacuum est extrêmement limité. Il ne fait qu'indiquer les
>>>>> espaces
>>>>> réutilisables sans forcer leur réutilisation. C'est le VACUUM FULL qui
>>>>> permet de regagné l'espace disque. Mais pour se faire il faut au moins
>>>>> avoir l'équivalent de la plus grosse table en espace disponible et
>>>>> verrouiller les tables en cours de traitement.
>>>>>
>>>>> Par ailleurs regagner l'espace disque n'est pas forcément une bonne
>>>>> idée, car, si je ne m'abuse, pgsql essaye d'insérer les données "au bon
>>>>> endroit". S'il y a des trous dans la base au bon endroit à cause d'une
>>>>> suppression précédente, c'est gagné, sinon il met là ou il peut.
>>>>>
>>>>> Ce sont les stats qui indique la meilleur stratégie.
>>>>>
>>>>> D'ailleurs, suivant l'espace disque disponible, il peut être judicieux
>>>>> de diminuer le fillfactor. ça laisse volontairement des trous dans la
>>>>> base pour insérer les nouvelles données
>>>>>
>>>>>
>>>>>
>>>>> Librement,
>>>>> --
>>>>> Christophe Merlet (RedFox)
>>>>>
>>>>> _______________________________________________
>>>>> dev-fr mailing list
>>>>> dev-fr at openstreetmap.org
>>>>> https://lists.openstreetmap.org/listinfo/dev-fr
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Christian Quest - OpenStreetMap France
>>>>
>>>> _______________________________________________
>>>> dev-fr mailing list
>>>> dev-fr at openstreetmap.org
>>>> https://lists.openstreetmap.org/listinfo/dev-fr
>>>>
>>>>
>>>
>>> _______________________________________________
>>> dev-fr mailing list
>>> dev-fr at openstreetmap.org
>>> https://lists.openstreetmap.org/listinfo/dev-fr
>>>
>>>
>>
>>
>> --
>> Christian Quest - OpenStreetMap France
>>
>> _______________________________________________
>> dev-fr mailing list
>> dev-fr at openstreetmap.org
>> https://lists.openstreetmap.org/listinfo/dev-fr
>>
>>
>
> _______________________________________________
> dev-fr mailing list
> dev-fr at openstreetmap.org
> https://lists.openstreetmap.org/listinfo/dev-fr
>
>
-------------- section suivante --------------
Une pièce jointe HTML a été nettoyée...
URL: <http://lists.openstreetmap.org/pipermail/dev-fr/attachments/20140812/5155c5b9/attachment-0001.html>
Plus d'informations sur la liste de diffusion dev-fr