DBA au service du développeur
Rodolphe Quiédeville
Meetup PostgreSQL Nantes
26 avril 2016
#mylife
Découvert Internet à 28.kbits avec Netscape Navigator
Utilise et produit du logiciel libre exclusivement
PostgreSQL depuis ... la 6.X ?
Consultant en performance des SI(G)
Senior Performance Engineer @PeopleDoc
Formateur Upstream University
SQL
ORM
Cas concret
Une observation du nombre d’oiseaux dans un espace fini
toutes les 5 minutes
Table ‘‘public.observation’’
Column | Type | Modifiers
----------+-----------------------------+---------------
obs_date | timestamp without time zone | default now()
duration | integer |
birds | integer |
Cas concret
Table des observations
pocpipe# select * from obs2 limit 5 ;
obs_date | duration | birds
---------------------+----------+-------
2000-01-01 00:00:00 | 4 | 67
2000-01-01 00:05:00 | 6 | 194
2000-01-01 00:10:00 | 17 | 273
2000-01-01 00:15:00 | 10 | 149
2000-01-01 00:20:00 | 4 | 77
Exploitation des données
Exploitation des données
SELECT
date_part ( ’ year ’ , obs_date ) ,
sum( birds ) : : f l o a t / sum( duration ) : : f l o a t
FROM observation
GROUP BY 1
ORDER BY 1 ASC ;
Non scalabilité
Le temps de réponse dépend du volume de données
Non scalabilité
Le temps de réponse dépend du volume de données
1 an de données 91 msec
Non scalabilité
Le temps de réponse dépend du volume de données
1 an de données 91 msec
4 ans de données 523 msec
Non scalabilité
Le temps de réponse dépend du volume de données
1 an de données 91 msec
4 ans de données 523 msec
12 ans de données 1495 msec
Mélange de données
Pour un graphique temps réel avec un historique conséquent
Mélange de données
Pour un graphique temps réel avec un historique conséquent
donnée froide (1,7M de tuples)
Mélange de données
Pour un graphique temps réel avec un historique conséquent
donnée froide (1,7M de tuples)
donnée chaude (toutes les 5 min)
Exploitation des données
SELECT
date_part ( ’ year ’ , obs_date ) ,
sum( birds ) : : f l o a t / sum( duration ) : : f l o a t
FROM observation
GROUP BY 1
ORDER BY 1 ASC ;
Exploitation des données
Gérer les données froides
CREATE MATERIALIZED VIEW observation_past AS
SELECT
date_part ( ’ year ’ , obs_date ) AS obs_year ,
SUM( birds ) : : f l o a t / SUM( duration ) : : f l o a t AS
birds_per_hour
FROM
observation
WHERE
date_part ( ’ year ’ , obs_date ) : : i n t < 2016
GROUP BY 1;
Time : 1275.701 ms
Exploitation des données froides
pocpipe#
SELECT * FROM observation_past
WHERE obs_year > 2010 ORDER BY obs_year;
obs_year | birds_per_hour
----------+------------------
2011 | 16.6410914009205
2012 | 16.6371300227029
2013 | 16.6985043384672
2014 | 16.6309208305199
2015 | 16.6618262419789
(5 rows)
Time: 0.609 ms
Exploitation des données chaudes
un peu plus complexe
appel à une solution extérieure
PipelineDB
www.pipelinedb.com
PostgreSQL Compatible
Continuous Aggregations
Sliding Window Queries
...
Le stream
Créer un stream pour alimenter la base
CREATE STREAM observations (
obs_date timestamp ,
duration int ,
birds i n t ) ;
La vue
Créer une vue pour consulter les données
CREATE CONTINUOUS VIEW observation_now AS
SELECT date_part ( ’ year ’ , obs_date ) AS obs_year ,
SUM( duration ) : : f l o a t AS sum_duration ,
SUM( birds ) : : f l o a t AS sum_birds
FROM
observations
WHERE
date_part ( ’ year ’ , obs_date ) >= 2016
GROUP BY
date_part ( ’ year ’ , obs_date ) ;
Le DBA au service du développeur
On va jouer à domicile :
CREATE EXTENSION postgres_fdw ;
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS ( host ’ 127.0.0.1 ’ , port ’ 9203 ’ ,
dbname ’ p ip el ine ’ ) ;
CREATE USER MAPPING FOR rodo
SERVER foreign_server
OPTIONS ( user ’ p ip eli ne ’ ,
password ’ pi pel in e ’ ) ;
Le DBA au service du développeur
La table locale pour alimenter le stream
CREATE FOREIGN TABLE observation_stream (
obs_date timestamp ,
duration int ,
birds i n t )
SERVER foreign_server
OPTIONS (
schema_name ’ public ’
, table_name ’ observations ’
, updatable ’ true ’ ) ;
Le DBA au service du développeur
La table locale pour récupérer les données
CREATE FOREIGN TABLE observation_now (
obs_year int ,
sum_duration int ,
sum_birds i n t )
SERVER foreign_server
OPTIONS (
schema_name ’ public ’
, table_name ’ observation_now ’
, updatable ’ false ’ ) ;
Toujours vide
pocpipe# select * from observation_now ;
obs_year | sum_duration | sum_birds
----------+--------------+-----------
(0 rows)
Alimentons pipelinedb
On va automatiser l’alimentation
CREATE OR REPLACE FUNCTION observation_feed_stream ( )
RETURNS TRIGGER AS $BODY$
BEGIN
INSERT INTO observation_stream
VALUES (NEW. obs_date ,
NEW. duration ,
NEW. birds ) ;
RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql ;
CREATE TRIGGER observation_trigger
AFTER INSERT ON observation FOR EACH ROW
EXECUTE PROCEDURE observation_feed_stream ( ) ;
Alimentons pipelinedb
Reprise d’historique
INSERT INTO observation_stream
(SELECT ∗ FROM observation where
date_part ( ’ year ’ , obs_date ) = 2016 ) ;
INSERT 0 33409
Toujours vide ?
pocpipe# select * from observation_now ;
obs_year | sum_duration | sum_birds
----------+--------------+-----------
2016 | 299864 | 5010160
(1 row)
Time: 4.179 ms
Toujours vide ?
pocpipe# select * from observation_now ;
obs_year | sum_duration | sum_birds
----------+--------------+-----------
2016 | 299864 | 5010160
(1 row)
Time: 4.179 ms
pocpipe# INSERT INTO observation VALUES (now(), 30, 200);
INSERT 0 1
Time: 9.904 ms
Toujours vide ?
pocpipe# select * from observation_now ;
obs_year | sum_duration | sum_birds
----------+--------------+-----------
2016 | 299864 | 5010160
(1 row)
Time: 4.179 ms
pocpipe# INSERT INTO observation VALUES (now(), 30, 200);
INSERT 0 1
Time: 9.904 ms
pocpipe# select * from observation_now ;
obs_year | sum_duration | sum_birds
----------+--------------+-----------
2016 | 299894 | 5010360
(1 row)
Time: 1.194 ms
One Shot
Dernière vue
CREATE OR REPLACE VIEW observation_all AS
WITH cte AS (
SELECT obs_year , birds_per_hour FROM observation_past
UNION ALL
SELECT
obs_year , sum_birds : : f l o a t / sum_duration : : f l o a t AS
birds_per_hour
FROM observation_now )
SELECT obs_year , birds_per_hour FROM cte ;
Badoum Ba !
pocpipe# select * from observation_all order by 1;
obs_year | birds_per_hour
----------+------------------
2000 | 16.6203813775456
2001 | 16.6695899394653
2002 | 16.6471423597847
2003 | 16.5756814747212
2004 | 16.6575399685407
2005 | 16.6397299509002
2006 | 16.6371339270242
2007 | 16.6560480162363
2008 | 16.6965677534587
2009 | 16.6812852231278
2010 | 16.6404274047321
2011 | 16.6410914009205
2012 | 16.6371300227029
2013 | 16.6985043384672
2014 | 16.6309208305199
2015 | 16.6618262419789
2016 | 16.7081076754795
(17 rows)
Time: 4.211 ms
En résumé
On remplace une table par une vue
et
SELECT
date_part ( ’ year ’ , obs_date ) AS obs_year ,
SUM( birds ) : : f l o a t / SUM( duration ) : : f l o a t AS
birds_per_hour
FROM
observation
GROUP BY 1;
par
SELECT obs_year , birds_per_hour FROM observation_all ;
En résumé
Temps de requête passe de 2723 ms à 1.962 ms
Questions ?
Rodolphe Quiédeville
rodolphe.quiedeville@people-doc.com
Document publié sous Licence Creative Commons BY-SA 2.0

PostgreSQL Meetup Nantes #2

  • 1.
    DBA au servicedu développeur Rodolphe Quiédeville Meetup PostgreSQL Nantes 26 avril 2016
  • 2.
    #mylife Découvert Internet à28.kbits avec Netscape Navigator Utilise et produit du logiciel libre exclusivement PostgreSQL depuis ... la 6.X ? Consultant en performance des SI(G) Senior Performance Engineer @PeopleDoc Formateur Upstream University
  • 3.
  • 4.
  • 5.
    Cas concret Une observationdu nombre d’oiseaux dans un espace fini toutes les 5 minutes Table ‘‘public.observation’’ Column | Type | Modifiers ----------+-----------------------------+--------------- obs_date | timestamp without time zone | default now() duration | integer | birds | integer |
  • 6.
    Cas concret Table desobservations pocpipe# select * from obs2 limit 5 ; obs_date | duration | birds ---------------------+----------+------- 2000-01-01 00:00:00 | 4 | 67 2000-01-01 00:05:00 | 6 | 194 2000-01-01 00:10:00 | 17 | 273 2000-01-01 00:15:00 | 10 | 149 2000-01-01 00:20:00 | 4 | 77
  • 7.
  • 8.
    Exploitation des données SELECT date_part( ’ year ’ , obs_date ) , sum( birds ) : : f l o a t / sum( duration ) : : f l o a t FROM observation GROUP BY 1 ORDER BY 1 ASC ;
  • 9.
    Non scalabilité Le tempsde réponse dépend du volume de données
  • 10.
    Non scalabilité Le tempsde réponse dépend du volume de données 1 an de données 91 msec
  • 11.
    Non scalabilité Le tempsde réponse dépend du volume de données 1 an de données 91 msec 4 ans de données 523 msec
  • 12.
    Non scalabilité Le tempsde réponse dépend du volume de données 1 an de données 91 msec 4 ans de données 523 msec 12 ans de données 1495 msec
  • 13.
    Mélange de données Pourun graphique temps réel avec un historique conséquent
  • 14.
    Mélange de données Pourun graphique temps réel avec un historique conséquent donnée froide (1,7M de tuples)
  • 15.
    Mélange de données Pourun graphique temps réel avec un historique conséquent donnée froide (1,7M de tuples) donnée chaude (toutes les 5 min)
  • 16.
    Exploitation des données SELECT date_part( ’ year ’ , obs_date ) , sum( birds ) : : f l o a t / sum( duration ) : : f l o a t FROM observation GROUP BY 1 ORDER BY 1 ASC ;
  • 17.
    Exploitation des données Gérerles données froides CREATE MATERIALIZED VIEW observation_past AS SELECT date_part ( ’ year ’ , obs_date ) AS obs_year , SUM( birds ) : : f l o a t / SUM( duration ) : : f l o a t AS birds_per_hour FROM observation WHERE date_part ( ’ year ’ , obs_date ) : : i n t < 2016 GROUP BY 1; Time : 1275.701 ms
  • 18.
    Exploitation des donnéesfroides pocpipe# SELECT * FROM observation_past WHERE obs_year > 2010 ORDER BY obs_year; obs_year | birds_per_hour ----------+------------------ 2011 | 16.6410914009205 2012 | 16.6371300227029 2013 | 16.6985043384672 2014 | 16.6309208305199 2015 | 16.6618262419789 (5 rows) Time: 0.609 ms
  • 19.
    Exploitation des donnéeschaudes un peu plus complexe appel à une solution extérieure
  • 20.
  • 21.
    Le stream Créer unstream pour alimenter la base CREATE STREAM observations ( obs_date timestamp , duration int , birds i n t ) ;
  • 22.
    La vue Créer unevue pour consulter les données CREATE CONTINUOUS VIEW observation_now AS SELECT date_part ( ’ year ’ , obs_date ) AS obs_year , SUM( duration ) : : f l o a t AS sum_duration , SUM( birds ) : : f l o a t AS sum_birds FROM observations WHERE date_part ( ’ year ’ , obs_date ) >= 2016 GROUP BY date_part ( ’ year ’ , obs_date ) ;
  • 23.
    Le DBA auservice du développeur On va jouer à domicile : CREATE EXTENSION postgres_fdw ; CREATE SERVER foreign_server FOREIGN DATA WRAPPER postgres_fdw OPTIONS ( host ’ 127.0.0.1 ’ , port ’ 9203 ’ , dbname ’ p ip el ine ’ ) ; CREATE USER MAPPING FOR rodo SERVER foreign_server OPTIONS ( user ’ p ip eli ne ’ , password ’ pi pel in e ’ ) ;
  • 24.
    Le DBA auservice du développeur La table locale pour alimenter le stream CREATE FOREIGN TABLE observation_stream ( obs_date timestamp , duration int , birds i n t ) SERVER foreign_server OPTIONS ( schema_name ’ public ’ , table_name ’ observations ’ , updatable ’ true ’ ) ;
  • 25.
    Le DBA auservice du développeur La table locale pour récupérer les données CREATE FOREIGN TABLE observation_now ( obs_year int , sum_duration int , sum_birds i n t ) SERVER foreign_server OPTIONS ( schema_name ’ public ’ , table_name ’ observation_now ’ , updatable ’ false ’ ) ;
  • 26.
    Toujours vide pocpipe# select* from observation_now ; obs_year | sum_duration | sum_birds ----------+--------------+----------- (0 rows)
  • 27.
    Alimentons pipelinedb On vaautomatiser l’alimentation CREATE OR REPLACE FUNCTION observation_feed_stream ( ) RETURNS TRIGGER AS $BODY$ BEGIN INSERT INTO observation_stream VALUES (NEW. obs_date , NEW. duration , NEW. birds ) ; RETURN NEW; END; $BODY$ LANGUAGE plpgsql ; CREATE TRIGGER observation_trigger AFTER INSERT ON observation FOR EACH ROW EXECUTE PROCEDURE observation_feed_stream ( ) ;
  • 28.
    Alimentons pipelinedb Reprise d’historique INSERTINTO observation_stream (SELECT ∗ FROM observation where date_part ( ’ year ’ , obs_date ) = 2016 ) ; INSERT 0 33409
  • 29.
    Toujours vide ? pocpipe#select * from observation_now ; obs_year | sum_duration | sum_birds ----------+--------------+----------- 2016 | 299864 | 5010160 (1 row) Time: 4.179 ms
  • 30.
    Toujours vide ? pocpipe#select * from observation_now ; obs_year | sum_duration | sum_birds ----------+--------------+----------- 2016 | 299864 | 5010160 (1 row) Time: 4.179 ms pocpipe# INSERT INTO observation VALUES (now(), 30, 200); INSERT 0 1 Time: 9.904 ms
  • 31.
    Toujours vide ? pocpipe#select * from observation_now ; obs_year | sum_duration | sum_birds ----------+--------------+----------- 2016 | 299864 | 5010160 (1 row) Time: 4.179 ms pocpipe# INSERT INTO observation VALUES (now(), 30, 200); INSERT 0 1 Time: 9.904 ms pocpipe# select * from observation_now ; obs_year | sum_duration | sum_birds ----------+--------------+----------- 2016 | 299894 | 5010360 (1 row) Time: 1.194 ms
  • 32.
    One Shot Dernière vue CREATEOR REPLACE VIEW observation_all AS WITH cte AS ( SELECT obs_year , birds_per_hour FROM observation_past UNION ALL SELECT obs_year , sum_birds : : f l o a t / sum_duration : : f l o a t AS birds_per_hour FROM observation_now ) SELECT obs_year , birds_per_hour FROM cte ;
  • 33.
    Badoum Ba ! pocpipe#select * from observation_all order by 1; obs_year | birds_per_hour ----------+------------------ 2000 | 16.6203813775456 2001 | 16.6695899394653 2002 | 16.6471423597847 2003 | 16.5756814747212 2004 | 16.6575399685407 2005 | 16.6397299509002 2006 | 16.6371339270242 2007 | 16.6560480162363 2008 | 16.6965677534587 2009 | 16.6812852231278 2010 | 16.6404274047321 2011 | 16.6410914009205 2012 | 16.6371300227029 2013 | 16.6985043384672 2014 | 16.6309208305199 2015 | 16.6618262419789 2016 | 16.7081076754795 (17 rows) Time: 4.211 ms
  • 34.
    En résumé On remplaceune table par une vue et SELECT date_part ( ’ year ’ , obs_date ) AS obs_year , SUM( birds ) : : f l o a t / SUM( duration ) : : f l o a t AS birds_per_hour FROM observation GROUP BY 1; par SELECT obs_year , birds_per_hour FROM observation_all ;
  • 35.
    En résumé Temps derequête passe de 2723 ms à 1.962 ms
  • 36.