8. PostgreSQL - Story
Développée à Berkeley
Réécriture de Ingres
1985 -> Postgres (vient de Post-Ingres)
1995 -> Postgres95 (0.01) (Ajout d’un interpréter SQL)
1997 -> PostgreSQL 6.0
2013 -> PostgreSQL 9.3
2014 -> PostgreSQL 9.4 (b4)
9. PostgreSQL - TL;DR
ORDBMS, ACID
SQL:2011
DataTypes
Transactional DDL
Concurrent Index
Extensions
Common Table Expression
MultiVersion Concurrency Control
Cross-Platform
10. PostgreSQL - TL;DR
Replication
Foreign Data Wrappers
Procedural Languages
Triggers
Full text Search
Views (Materialized)
Table Inheritance
Listen/Notify
11. PostgreSQL, FDW ?
Utiliser une source externe à PostgreSQL
Twitter, RSS, CSV, XML
FileSystem
Processes
12. PostgreSQL, PL ?
Étend la base de données
Fonctions stockées
Safe (sandbox, SQL, PL/pgSQL) / Unsafe (C)
PL/Python, PL/V8, PL/PERL
14. DB-API 2.0 aka PEP-249
API pour les connecteurs de Base de Données
Facile à utiliser, et à comprendre
Utilise deux concepts:
• Connection
• Curseur
http://legacy.python.org/dev/peps/pep-0249/
15. Connection
Emballe une connection vers la base de données
Gère les transactions et leur état (Commit/
Rollback)
N’exécute pas de requêtes SQL.
17. Connection - Exemple
import driver
conn = driver.connect(database='database',
host='localhost',
port=5432)
try:
# cree le curseur
# utilise le curseur
except Exception:
conn.rollback()
else:
conn.commit()
conn.close()
18. Curseur
Créé via une instance d’une connection
Utilisé pour la manipulation et interrogation de la
Base de Données
cursor = conn.cursor()
cursor.execute("""
SELECT column1, column2
FROM tableA
""")
for column1, column2 in cursor.fetchall():
print(column1, column2)
20. Curseur - execute
execute(query[, parameters])
Performance et Sécurité
JAMAIS utiliser l’interpolation (%)
et la concaténation (+)
=> SQL Injection
21. Curseur - execute (2)
Accepte un formatage de la requête.
qmark Question mark WHERE field = ?
numeric Numeric positional WHERE field = :1
named Named WHERE field = :code
format ANSI C print format WHERE field = %s
pyformat Python format WHERE field = %(name)s
22. Exemple plus complet ;-)
import driver
conn = driver.connect(database='database',
host='localhost',
port=5432)
cursor = conn.cursor()
try:
cursor.execute("SELECT column1, column2 FROM tableA")
for column1, column2 in cursor.fetchall():
print(column1, column2)
except Exception:
conn.rollback()
else:
conn.commit()
finally:
cursor.close()
conn.close()
24. Introduction
PostgreSQL Adaptor, basé sur libpq
DB-API 2.0 Compliant
Multi-thread
Pool de Connections
Full Asynchronous, Coroutines
Supporte TOUS les types de données de PostgreSQL (Json,
Hstore, …)
Python 2.5+, 3.1+, PostgreSQL 7.4+
25. Curseurs
cursor = conn.cursor()
cursor = conn.cursor(name=“pycon_cursor”)
• Curseur coté PostgreSQL
• Interrogation, manipulation des données de la
base.
• Nommé => Utilisé pour les gros ensembles de
données
26. Requêtes SQL
cursor.execute("SELECT * FROM table")
cursor.execute("INSERT INTO table (field1, field2) VALUES (%s, %s)",
(field1, field2))
cursor.execute("DELETE FROM table")
cursor.execute("UPDATE table SET field1=%s", ('value',))
cursor.execute("CREATE DATABASE database")
cursor.execute("DROP DATABASE database")
27. Exemple
import psycopg2
conn = psycopg2.connect(host='localhost', port=5432,
user='username', password='password',
database='database')
cursor = conn.cursor()
try:
cursor.execute("SELECT column1, column2 FROM tableA")
for column1, column2 in cursor.fetchall():
print(column1, column2)
except Exception:
conn.rollback()
else:
conn.commit()
finally:
cursor.close()
conn.close()
28. Exemple - Context Manager
import psycopg2
DSN = dict(host='localhost', port=5432,
user='username', password='password',
database='database')
with psycopg2.connect(**DSN) as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT column1, column2 FROM tableA")
for column1, column2 in cursor.fetchall():
print(column1, column2)
conn.commit()
30. Introduction
“Technique de Programmation créant l’illusion
d’une base de données orientée objet à partir
d’une base de données relationnelle en définissant
des correspondances entre cette base de
données et les objets du langage utilisé.”
Wikipedia
31. En bref
• Mapper une classe Business sur une table !
• Méthodes pour ajouter, modifier, supprimer et
rechercher
33. Peewee
ORM
Simple, facile à comprendre et extensible
Python 2.6+ et 3.2+
Extensions
3200 lignes de code (MySQL, Sqlite3 et PostgreSQL)
Très bonne documentation
53. Alembic
Basé sur SQLAlchemy
Utilise un environnement de Migration
Fichier de configuration INI
Scripts de migration
http://alembic.readthedocs.org/
54. Alembic
cd votreproject
alembic init migrations
> tree
migrations/
!"" README
!"" alembic.ini
!"" env.py
!"" script.py.mako
#"" versions
64. Multicorn
• Extension PostgreSQL
• Permet d’écrire un Foreign Data Wrapper
• Wrapper Python de l’API C de PostgreSQL
• Tous les outils utilisant SQL peuvent utiliser un
FDW
• Support FULL SQL ;-)
65. FDW de base
• RSS, CSV, XML
• LDAP
• Gmail, IMAP
• Google Search
• SQLAlchemy (mysql, sqlite, oracle, …)
67. Simple exemple (2)
CREATE SERVER wirtel_be_srv
FOREIGN DATA WRAPPER multicorn
OPTIONS (
wrapper 'multicorn.rssfdw.RssFdw'
);
CREATE FOREIGN TABLE wirtel_be_rss (
"pubDate" TIMESTAMP,
description CHARACTER VARYING,
title CHARACTER VARYING,
link CHARACTER VARYING
) SERVER wirtel_be_srv OPTIONS(
url 'http://wirtel.be/feeds/python.rss.xml'
);
68. Simple exemple (3)
SELECT "pubDate", title, link FROM wirtel_be_rss LIMIT 1;
-[ RECORD 1 ]------------------------------------------------------------------------
pubDate | 2014-10-19 00:00:00
title | Python @ FOSDEM 2015 - Call For Proposals
link | http://wirtel.be/posts/en/2014/10/19/python-fosdem-2015-call-for-proposals/
69. avec OpenERP
from multicorn import ForeignDataWrapper
import erppeek
class OpenERPForeignDataWrapper(ForeignDataWrapper):
def __init__(self, options, columns):
super(OpenERPForeignDataWrapper, self).__init__(options, columns)
url = 'http://{hostname}:{password}'.format(**options)
self.client = erppeek.Client(url,
options['database'],
options['username'],
options['password'])
self.object_name = options['object']
def execute(self, quals, columns):
proxy = self.client.model(self.object_name)
item = {}
for record in proxy.browse([]):
for column in columns:
item[column] = record[column]
yield item
70. avec OpenERP (2) CREATE EXTENSION multicorn;
CREATE SERVER multicorn_openerp
FOREIGN DATA WRAPPER multicorn
OPTIONS (wrapper 'multicorn.openerpfdw.OpenERPForeignDataWrapper');
CREATE FOREIGN TABLE oe_users (
login character varying,
name character varying)
SERVER multicorn_openerp OPTIONS (
hostname 'localhost',
port '8069',
database 'openerp',
username 'admin',
password 'admin',
object 'res.users'
);
SELECT id, login, name, active
FROM oe_users
WHERE login = 'admin';
74. PL/Python
CREATE OR REPLACE FUNCTION str_title(s VARCHAR) RETURNS VARCHAR AS $$
return s.title()
$$ LANGUAGE plpythonu;
demo=# select str_title('hello world');
-[ RECORD 1 ]----------
str_title | Hello World
75. PL/Python - DataTypes
PostgreSQL Python
integer, bigint int, long
boolean bool
text types str
SQL Array list
Custom Types dict
76. PL/Python - Debug
Fonctions de base pour afficher les messages
• plpy.notice(“<msg>”)
• plpy.debug(“<msg>”)
• plpy.error(“<msg>”)
• plpy.fatal(“<msg>”)
Oublier le ”print”
77. PL/Python
CREATE OR REPLACE FUNCTION get_pid_cpu_mem(pid INT)
RETURNS TABLE(pid INT, cpu_perc FLOAT, mem_perc FLOAT) AS $$
import psutil
process = psutil.Process(pid)
return [
{
'pid': pid,
'cpu_perc': process.get_cpu_percent(interval=0),
'mem_perc': process.get_memory_percent()
}
]
$$ LANGUAGE plpythonu;
80. PL/Python
WITH stats AS (
SELECT psa.*, get_pid_cpu_mem(psa.pid) as attrs
from pg_stat_activity psa
)
SELECT (stats.attrs).pid,
(stats.attrs).cpu_perc,
(stats.attrs).mem_perc,
stats.application_name
FROM stats;
pid | cpu_perc | mem_perc | application_name
-------+----------+---------------+------------------
14680 | 0 | 1.50435626678 | psql
(1 row)
81. PL/Python - Attention
Unsafe -> pas de sandbox
Difficile à maintenir et à debugger
Comment rendre fou votre DBA ;-)
Pas de virtualenv et demande les privilèges
superuser.
82. PL/Python - Pistes ;-)
Traitement sur grosses masses de données
Ajouter des contraintes fortes et logique dans le système.
Ajouter de nouvelles fonctionnalités dans PostgreSQL
“str_title”
Triggers ?
Utilisation des libs de PyPI (requests, redis, zmq, smtp…)
Accès complet à la base de données !!!