Prendre un thé
Tapoter des doights
Monsieur fantôme
Quelle heure est-il ?
BazinGa's Tips & tuto IT
BazinGa's - Tips & tuto IT

Auditer les données

Voici quelques éléments d’aide pour auditer efficacement les données.

PostgreSQL

Quelques informations sur le cluster de BDD

Vue : liste des BDD et informations.

CREATE OR REPLACE VIEW public.info_cluster_bdd AS
	SELECT
		pgdb.datname as "Nom",
		pga.rolname as "Propriétaire",
		pg_database_size(pgdb.datname) as "Taille en octets", 
		pg_size_pretty(pg_database_size(pgdb.datname)) as "Taille en Byte (Octets)",
		pgdb.encoding as "Encodage",
		pgdb.datcollate as "Collation",
		pgdb.datctype as "Classification des caractères",
		CASE
			WHEN pgdb.datallowconn IS TRUE
				THEN 
					CASE pgdb.datconnlimit
						WHEN -1 THEN 'Nombre illimité de connexion'
						WHEN 1 THEN '1 connexion max'
						ELSE pgdb.datconnlimit || ' connexions simultanées max'
					END
			ELSE 'Connexion non autorisée'
		END as "Connectivité",
		CASE
			WHEN pgdb.datistemplate IS TRUE
				THEN 'Base template'
			ELSE 'Base standard'
		END as "Modèle",
		pgdb.datacl as "Droits"
	FROM
		pg_database pgdb
	LEFT JOIN
		pg_authid as pga
	ON
		pgdb.datdba = pga.oid
	ORDER BY
		pgdb.datname;

Vue : Activité en temps réelle.

CREATE OR REPLACE VIEW public.info_cluster_activite AS
SELECT
	pid as "Processus",
    datname as "BDD",
    usename as "Utilisateur",
    client_addr || ':' || client_port as "Client",
    CASE state
    	WHEN 'active' THEN 'En cours'
        WHEN 'idle' THEN 'En attente du client'
        WHEN 'idle in transaction' THEN 'En transaction sans exécution de requête'
        WHEN 'idle in transaction (aborted)' THEN 'En transaction sans exécution de requête mais l''une des instruction a généré une erreur'
        WHEN 'fastpath function call' THEN 'Le processus exécute une fonction fast-path'
        WHEN 'disabled' THEN 'Traçage d''activité désactivé'
    END as "Etat",
    CASE wait_event_type
		WHEN 'LWLockNamed' THEN 'En attente du verrou léger ' || wait_event
		WHEN 'LWLockTranche' THEN 'En attente d''un verrou léger : ' || wait_event
		WHEN 'Lock' THEN 'En attente du verrou lourd de type ' || wait_event
		WHEN 'BufferPin' THEN 'En attente d''accès à un tampon'
		ELSE 'Aucun verrou'
    END as "Verrou",
    date_trunc('second', justify_hours(age(now(), pg_stat_activity.backend_start))) AS "Démarrage processus",
    date_trunc('second', justify_hours(age(now(), pg_stat_activity.xact_start))) AS "Démarrage transaction",
    date_trunc('second', justify_hours(age(now(), pg_stat_activity.query_start))) AS "Démarrage dernière requête",
    date_trunc('second', justify_hours(age(now(), pg_stat_activity.state_change))) AS "Modification de l''état",
    query as "Requête"
FROM
	pg_stat_activity
ORDER BY
	"Modification de l''état",
	"Démarrage dernière requête",
	"Démarrage processus";

Vue : rôles.

CREATE OR REPLACE VIEW public.info_cluster_role AS
	SELECT
	    pga.rolname as "Rôle",
	    concat_ws(', ',pga2.rolname) as "Membre du rôle",
	    CASE
	        WHEN pga.rolsuper IS TRUE
	            THEN 'Super utilisateur'
	        ELSE 'Simple utilisateur'
	    END as "Surper administration",
	    CASE
	        WHEN pga.rolcreaterole IS TRUE
	            THEN 'Oui'
	        ELSE 'Non'
	    END as "Création d'autres rôles",
	    CASE
	        WHEN pga.rolcreatedb IS TRUE
	            THEN 'Oui'
	        ELSE 'Non'
	    END as "Création de BDD",
	    CASE
	        WHEN pga.rolcanlogin IS TRUE
	            THEN 'Oui'
	        ELSE 'Non'
	    END as "Possibilité de connexion",
	    CASE
	        WHEN pga.rolconnlimit = -1
	            THEN 'Illimité'
	        WHEN pga.rolconnlimit = 0
	            THEN 'Aucune'
	        WHEN pga.rolconnlimit = 1
	            THEN '1 seule connexion simmultanée'
	        ELSE pga.rolconnlimit || ' connexions simultanées'
	    END as "Nombre de connexions simultanées",
	    CASE
	        WHEN pga.rolvaliduntil::text = 'infinity'
	            THEN 'Infini'
	        ELSE pga.rolvaliduntil::text
	    END as "Validité",
	    pga.rolpassword as "Mot de passe"
	FROM
	    pg_authid as pga
	LEFT JOIN
	    pg_auth_members as pgam
	ON 
	    pga.oid = pgam.member
	LEFT JOIN
	    pg_authid as pga2
	ON 
	    pga2.oid = pgam.roleid
	ORDER BY
	    pga.rolname;

Quelques informations sur la BDD

SELECT : liste des extensions

SELECT 
	t1.extname,
	t1.extversion,
	t2.nspname
FROM 
	pg_extension AS t1
LEFT JOIN 
	pg_namespace AS t2
ON 
	t1.extnamespace = t2.oid;

SELECT : liste des clés étrangères

SELECT 
	tc.constraint_name,
	tc.constraint_type,
	tc.table_name,
	kcu.column_name,
	rc.update_rule AS on_update,
	rc.delete_rule AS on_delete,
	ccu.table_name AS references_table,
	ccu.column_name AS references_field

FROM 
	information_schema.table_constraints tc

LEFT JOIN information_schema.key_column_usage kcu
	ON tc.constraint_catalog = kcu.constraint_catalog
	AND tc.constraint_schema = kcu.constraint_schema
	AND tc.constraint_name = kcu.constraint_name

LEFT JOIN information_schema.referential_constraints rc
	ON tc.constraint_catalog = rc.constraint_catalog
	AND tc.constraint_schema = rc.constraint_schema
	AND tc.constraint_name = rc.constraint_name

LEFT JOIN information_schema.constraint_column_usage ccu
	ON rc.unique_constraint_catalog = ccu.constraint_catalog
	AND rc.unique_constraint_schema = ccu.constraint_schema
	AND rc.unique_constraint_name = ccu.constraint_name

--- any conditions for table etc. filtering
WHERE lower(tc.constraint_type) in ('foreign key', 'primary key')

Quelques statistiques sur la BDD

Attention, il faut faire un ANALYSE sur la BDD avant de lancer les scripts.

Vue : liste des schémas

CREATE OR REPLACE VIEW public.info_bdd_general AS
	SELECT
		it.table_schema as "Schéma",
		count(it.table_name) as "Nombre de tables", 
		sum(pgc.reltuples) as "Nombre d'enregistrement",
		pg_size_pretty(sum(pg_relation_size('"' || it.table_schema || '"."' || it.table_name || '"'))) as "Taille des données",
		pg_size_pretty(sum(pg_total_relation_size('"' || it.table_schema || '"."' || it.table_name || '"'))) as "Taille totale"

	FROM
		information_schema.tables as it
	LEFT JOIN 
		pg_namespace pgn 
	ON 
		pgn.nspname = it.table_schema::name
	LEFT JOIN 
		pg_class pgc 
	ON 
		(pgc.relname = it.table_name::name 
		AND pgc.relnamespace = pgn.oid)
	WHERE 
		table_type = 'BASE TABLE'
	GROUP BY
		it.table_schema
	ORDER BY
		it.table_schema;

Vue : liste des tables

D’abord on créé une fonction.

CREATE OR REPLACE FUNCTION public.type_colonne_geom(mon_schema text, ma_table text)
RETURNS text AS

$CORPS$

DECLARE
	nom_colonne text[];
	resultat text;

BEGIN
	nom_colonne = array(
		SELECT
			column_name::text 
		FROM
			information_schema.columns 
		WHERE
			table_schema=mon_schema
		AND
			table_name=ma_table
		AND
			column_name ~ '(^(geom)$|^(GEOM)$|^(the_geom)$|^(THE_GEOM)$)'
		)
	;

	mon_schema = quote_ident(mon_schema);
	ma_table = quote_ident(ma_table);

	IF array_length(nom_colonne,1) > 1
		THEN resultat = '/!\ Plusieurs colonnes géométriques /!\ ';
	ELSEIF array_length(nom_colonne,1) = 1
		THEN 
			EXECUTE '
				SELECT
					''Géometrie ('' || GeometryType(t1."'|| array_to_string(nom_colonne,'') ||'") || '', '' || ST_NDims (t1."'|| array_to_string(nom_colonne,'') ||'") ||''D, '' || ST_SRID (t1."'|| array_to_string(nom_colonne,'') ||'") || '')''
				FROM
					'|| mon_schema || '.' || ma_table ||' as t1;
				'
			INTO
				resultat
			;
	ELSE
		resultat = 'Non géométrique';
	END IF;

	IF resultat IS NULL
		THEN resultat = 'Pas de données dans la table';
	END IF;

	RETURN resultat;
END;

$CORPS$

LANGUAGE PLPGSQL
;

Ensuite on créé la vue qui va bien.

CREATE OR REPLACE VIEW public.info_bdd_table AS
SELECT
	it.table_schema as "Schéma",
	it.table_name as "Table",
	CASE 
		 WHEN pgc.reltuples = 0
		 	THEN 'Aucun enregistrement pour cette table'
		 WHEN pgc.reltuples = 1
		 	THEN pgc.reltuples || ' enregitrement'
		 ELSE pgc.reltuples || ' enregistrements'
	END as "Nombre d'enregistrement",
	pg_size_pretty(pg_relation_size('"' || it.table_schema || '"."' || it.table_name || '"')) as "Taille des données",
	pg_size_pretty(pg_total_relation_size('"' || it.table_schema || '"."' || it.table_name || '"')) as "Taille totale",
	public.type_colonne_geom(it.table_schema, it.table_name) AS "Informations géométriques",
	pgd.description as "Commentaire"

FROM
	information_schema.tables as it

LEFT JOIN
	pg_namespace AS pgn
ON
	it.table_schema = pgn.nspname
LEFT JOIN
	pg_class AS pgc
ON
	(it.table_name = pgc.relname AND pgn.oid = pgc.relnamespace)
LEFT JOIN
	pg_description AS pgd
ON
	(pgc.oid = pgd.objoid AND 0 = pgd.objsubid)
WHERE
	it.table_schema != 'pg_catalog'
AND
	it.table_schema != 'information_schema'
ORDER BY
	it.table_schema,
	it.table_name;

Vue : liste des colonnes

Attention, il faut créer la fonction décrite dans le paragraphe précédent.

CREATE OR REPLACE VIEW public.info_bdd_colonne AS
SELECT
	ic.table_catalog as "Base de données",
	ic.table_schema as "Schéma",
	ic.table_name as "Table",
	ic.column_name as "Colonne",
	CASE
		WHEN ic.data_type = 'USER-DEFINED'
		THEN public.type_colonne_geom(ic.table_schema, ic.table_name)
		ELSE ic.data_type ||
			CASE
				WHEN ic.character_maximum_length IS NOT NULL
				THEN ' (' || ic.character_maximum_length || ')'
				WHEN ic.numeric_precision IS NOT NULL
				THEN ' (' || ic.numeric_precision::text || ', ' || ic.numeric_precision_radix::text || ')'
				ELSE ''
			END
		END
		as "Type de données",
	pgd.description as "Commentaire"
FROM
	information_schema.columns AS ic
LEFT JOIN
	pg_namespace AS pgn
ON
	ic.table_schema = pgn.nspname
LEFT JOIN
	pg_class AS pgc
ON
	(ic.table_name = pgc.relname AND pgn.oid = pgc.relnamespace)
LEFT JOIN
	pg_description AS pgd
ON
	(pgc.oid = pgd.objoid AND ic.ordinal_position = pgd.objsubid)
WHERE
	ic.table_schema != 'pg_catalog'
AND
	ic.table_schema != 'information_schema'
ORDER BY
	ic.table_catalog,
	ic.table_schema,
	ic.table_name,
	ic.column_name,
	ic.ordinal_position;

Vue : liste des table et colonnes portants des commentaires

CREATE OR REPLACE VIEW public.info_bdd_commentaire AS
SELECT 
	it.table_schema AS "Nom schéma",
	it.table_name AS "Nom table",
	CASE
		WHEN ic.column_name IS NULL
		THEN '-TABLE-'
		ELSE ic.column_name
	END AS "Nom colonne",
	pgd.description AS "Commentaire"
FROM
	pg_description AS pgd
LEFT JOIN
	pg_class AS pgc
ON
	pgd.objoid = pgc.oid
LEFT JOIN
	information_schema.tables AS it
ON
	pgc.relname = it.table_name
LEFT JOIN
	information_schema.columns AS ic
ON
	(pgc.relname = ic.table_name AND ic.ordinal_position = pgd.objsubid)
WHERE
	it.table_schema != 'pg_catalog'
AND
	it.table_schema != 'information_schema'
ORDER BY
	it.table_schema,
	it.table_name,
	ic.ordinal_position;

Oracle

Quelques informations sur la BDD

SELECT : liste des tables et informations

Tips : il est possible d’ajouter une clause WHERE pour limiter le résultat à un seul schéma.

SELECT 
	t1.owner AS "Proprietaire",
	t1.table_name AS "Table",
	t1.tablespace_name AS "Tablespace",
	t1.num_rows AS "Nbr ligne",
	round(t1.blocks*t2.BLOCK_SIZE/1024,2) AS "Taille ko",
	round(t1.blocks*t2.BLOCK_SIZE/1024/1024,2) AS "Taille Mo",
	round(t1.blocks*t2.BLOCK_SIZE/1024/1024/1024,2) AS "Taille Go"
FROM
	all_tables t1
LEFT JOIN 
	user_tablespaces t2
	ON t1.tablespace_name = t2.tablespace_name
ORDER BY 1,2;

Les fichiers

Lister les fichiers et leurs informations

Voici un petit script Batch à copier dans un fichier .bat qui va analyser les fichiers présents dans le répertoire et les sous répertoires du .bat et créer un fichier CSV avec cette liste de fichier.

Ce script ne listera que les fichiers dont l’extension est définie dans la première partie.

Il est possible d’ajouter des extensions et d’ajouter des information pour chaque extension (avec la clé param.type[X].info).

@echo off
chcp 1252

SETLOCAL enabledelayedexpansion

REM ========================
REM Définition des variables
REM ========================

REM Liste des types analysés
REM Vecteurs
SET param.type[0].ext=.shp
SET param.type[1].ext=.shx
SET param.type[2].ext=.dbf
SET param.type[3].ext=.tab
SET param.type[4].ext=.mif
SET param.type[5].ext=.mid
SET param.type[6].ext=.dxf
SET param.type[7].ext=.dwg
SET param.type[8].ext=.mdb
SET param.type[8].info=ESRI Geodatabase personnelle
SET param.type[9].ext=.thf
SET param.type[9].info=Edigéo
SET param.type[10].ext=.bna
SET param.type[10].info=Atlas BNA
SET param.type[11].ext=.xls
SET param.type[12].ext=.xlsx
SET param.type[13].ext=.gpx
SET param.type[13].info=GPS eXchange format
SET param.type[14].ext=.geojson
SET param.type[15].ext=.mdb
SET param.type[15].info=Access
SET param.type[16].ext=.kml
SET param.type[17].ext=.kmz
SET param.type[18].ext=.mbtiles
SET param.type[18].info=Mapbox tiles
SET param.type[19].ext=.dgn
SET param.type[19].info=Microstation DGN
SET param.type[20].ext=.sqlite
SET param.type[20].info=SQLite
SET param.type[21].ext=.db
SET param.type[21].info=SQLite
SET param.type[22].ext=.sqlite3
SET param.type[22].info=SQLite
SET param.type[23].ext=.db3
SET param.type[23].info=SQLite
SET param.type[24].ext=.csv

 

REM Raster
SET param.type[30].ext=.ecw
SET param.type[31].ext=.tif
SET param.type[32].ext=.tiff
SET param.type[33].ext=.jp2
SET param.type[34].ext=.j2k
SET param.type[35].ext=.xyz
SET param.type[36].ext=.asc
SET param.type[37].ext=.grd
SET param.type[38].ext=.dem
SET param.type[39].ext=.vrt



REM ===========================
REM Fin de configuration
REM ===========================



REM ===========================
REM Gestion des paramètres
REM ===========================

REM Liste des paramètres
SET param.dir_audit[0]=FALSE
SET param.dir_audit[1]=


REM Récupération des paramètres
SET parametre=%*

REM Initialisation de la prise en compte des paramètres
SET param_en_cours=
SET /a num_param=0

REM Récuépration des paramètres dans une variable spécifique
FOR %%a in (%parametre%) do (
	
	SET /a num_param+=1
	SET var=%%a

	IF "!var:~0,1!"=="-" (
		SET param_en_cours=%%a
		SET num_param=0
	)

	REM Récupération du paramètre d'emplacement des fichiers à analyser
	IF "!param_en_cours:~0,10!"=="-dir_audit" (
		SET param.dir_audit[0]=TRUE
		
		SET valeur=!var:~11!
		REM Inversion des slash
		SET valeur=!valeur:/=\!

		REM Retrait des guillemets
		SET valeur=!valeur:"=!

		REM Retrait du slash initial
		IF "!valeur:~0,1!"=="\" (
			SET valeur=!valeur:~1!
		)

		REM Retrait du slash final
		IF "!valeur:~-1!"=="\" (
			SET valeur=!valeur:~0,-1!
		)
		
		SET param.dir_audit[1]=!valeur!\
	)

)



REM ===========================
REM Variables internes
REM ===========================

REM Nettoyage vecteurs
FOR /L %%i in (0, 1, 29) do (

	SET param.type[%%i].type=Vecteur

	IF "!param.type[%%i].ext!"=="" (
		SET param.type[%%i].ext=
	)

	IF "!param.type[%%i].info!"=="" (
		SET param.type[%%i].info=
	)
)

REM Nettoyage rasters
FOR /L %%i in (30, 1, 39) do (

	SET param.type[%%i].type=Raster

	IF "!param.type[%%i].ext!"=="" (
		SET param.type[%%i].ext=
	)

	IF "!param.type[%%i].info!"=="" (
		SET param.type[%%i].info=
	)
)



REM Définition de la date et de l'heure
REM Heure de démarrage
SET var_start_time=%time%
SET var_start_date=%date%

SET var_date=%var_start_date:~6,4%-%var_start_date:~3,2%-%var_start_date:~0,2%
SET var_time=%var_start_time:~0,2%-%var_start_time:~3,2%-%var_start_time:~6,2%
SET var_date_time=%var_date%_%var_time%


REM Titre
SET titre=Audit de fichier
title %titre%


REM Récupération de l'emplacement du script
SET var_dir_install=%~dp0


REM Log
REM Nom du fichier de log
SET var_log_filename=%var_date_time%_audit_fichier.log

REM Localisation du fichier de log
SET var_log_dir=%var_dir_install%
SET var_log_file=%var_log_dir%%var_log_filename%


REM Nom du fichier d'audit
SET var_audit_filename=%var_date_time%_audit_fichier.csv

REM Localisation du fichier d'audit
SET var_audit_dir=%var_dir_install%
SET var_audit_file=%var_log_dir%%var_audit_filename%
 
IF %param.dir_audit[0]%==TRUE (
	SET var_repertoire_audit=%param.dir_audit[1]%
) ELSE (
	SET var_repertoire_audit=%var_dir_install%
)



REM ===========================
REM Fichiers en sortie
REM ===========================

REM Init log d'audit
(
	echo =======================================
	echo ==         %titre%          ==
	echo =======================================
	echo.
	echo Date d'execution : %var_start_date:~0,2%-%var_start_date:~3,2%-%var_start_date:~6,4%
	echo Heure d'execution : %var_start_time:~0,2%:%var_start_time:~3,2%:%var_start_time:~6,5%
	echo.
	echo Emplacement du script : 
	echo 	%var_dir_install%
	echo Emplacement du fichier d'audit : 
	echo 	%var_audit_file%
	echo Emplacement des fichiers audités : 
	echo 	%var_repertoire_audit%
	echo.
	echo.
	echo.
) > "%var_log_file%"



REM Init fichier d'audit
REM On définit les titre de cahque colonne
(
	echo Type;Fichier;Extension;Taille (octet^);Emplacement;Informations
) > "%var_audit_file%" 

REM Variables de statistiques
REM Nombre de fichiers
SET var_nb_fichier_total=0
REM Nombre de fichiers
SET var_nb_fichier_audit=0
REM Taille des fichiers
SET var_taille_fichier=0



REM ===========================
REM Traitement
REM ===========================

REM Pour chaque fichier
FOR /f "usebackq delims=|" %%f in (`dir /b /s /a-d "%var_repertoire_audit%"`) do (
	REM Comptage du nombre de fichiers analysés
	SET /a var_nb_fichier_total+=1

	REM Affichage du nombre de fichiers analysés
	REM echo !time:~0,2!:!time:~3,2!:!time:~6,5! : !var_nb_fichier_total! fichiers analysés

	REM Pour chaque type de fichier listé précédemment
	FOR /L %%i in (0, 1, 39) do (

		REM Si le type de fichier correspond
		IF "%%~xf"=="!param.type[%%i].ext!" (

			REM Mise à jour des statistiques
			SET /a var_nb_fichier_audit+=1
			SET /a var_taille_fichier+=%%~zf

			(echo !param.type[%%i].type!;%%~nf;%%~xf;%%~zf;%%~pf;!param.type[%%i].info!) >> "%var_audit_file%"
		)
	)
)


REM Calcul de la taille totale en Mégaoctets
SET /a var_taille_fichier_mo=%var_taille_fichier%/1024/1024

REM Statistiques
(
	echo Nombre total de fichiers analysés : %var_nb_fichier_total%
	echo Nombre total de fichiers SIG trouvés : %var_nb_fichier_audit%
	echo Taille totale de fichiers SIG trouvés : %var_taille_fichier_mo% Mo (%var_taille_fichier% octets^)
	echo.
	echo.
	echo Fin du traitement à %time:~0,2%:%time:~3,2%:%time:~6,5%
) >> "%var_log_file%" 


:eof
ENDLOCAL



Cet article vous a plu ?

N'hésitez pas à le partager, il interessera surement certains de vos contacts.

Les thèmes suivants contiennent des articles en lien avec celui-ci, allez faire un tour :

BDDOraclePostGISPostgreSQLSIG

50%