Vous n'êtes pas identifié(e).

#1 19/04/2010 13:39:55

R.Seif
Membre

optimisation de l'insertion et la selection

Bonjour,

Lors du programme si dessous, je veux insérer une @IP, tester son existance, me rendre un msg d'erreur (qui ne soit pas systématique) s'il existe, sinon on insère cette nouvelle @.

-- MAPE_ADD_IP
-- Takes a CIDR representation of the IP in input and adds a record in the ips table
-- returns the index of the entry
-- if the entry exists, returns simply the ID
--
CREATE OR REPLACE FUNCTION mape_add_ip(inet) RETURNS inet
AS $$
	DECLARE
        addr ALIAS FOR $1;
	md5ip varchar;
        ipid INTEGER;
BEGIN
	SELECT INTO ipid mape_get_ip(addr);

	IF ipid >= 1
		THEN
			return (addr);
		ELSE
			INSERT INTO ips(ip,md5) VALUES (addr,'-');
			--SELECT INTO ipid currval('ips_id_seq');
	END IF;
	
       	 return (addr);
END;$$
	LANGUAGE plpgsql;


-----------------------------------------------------------------------------------------
-- MAPE_GET_IP
-- Returns the ID of the given addr
--
CREATE OR REPLACE FUNCTION mape_get_ip(inet) RETURNS integer
AS $$
	DECLARE
	addr ALIAS FOR $1;
	ipid  INTEGER;
BEGIN
	SELECT INTO ipid ip FROM ips WHERE host(ips.ip) = host(addr);
IF ipid >=1
	THEN
		return ipid;

		ELSE
			return 0;
	END IF;
	
END;$$
	LANGUAGE plpgsql;



--

cette opération va se faire plusieurs fois, donc j'ai pensé utiliser INSERT ... RUNNING ... mais j'ai pas su comment l'utiliser?

Hors ligne

#2 19/04/2010 14:03:07

Marc Cousin
Membre

Re : optimisation de l'insertion et la selection

INSERT RETURNING ne sert pas dans votre cas, puisque vous retourneriez quelque chose que vous connaissez déjà.

Premier problème:
SELECT INTO ipid ip FROM ips WHERE host(ips.ip) = host(addr) n'utilisera pas d'index… et sera donc peu performant : vous appliquez une fonction à une colonne de votre table.

Ensuite, je vous conseille d'opter pour l'algorithme réussissant le plus souvent : quand mape_add_ip est appelé, quel sera le cas le plus fréquent : l'ip déjà en place, ou l'ip à insérer ? si c'est le second cas, commencez votre algo par une tentative d'insertion, puis interceptez l'erreur si nécessaire, plutôt que de d'abord tester la présence de l'enregistrement puis tenter l'insertion.

Dernier point qui me chiffonne : que se passe t'il si vous avez deux sessions voulant ajouter la même IP en même temps, que les deux voient par mape_get_ip que l'IP n'existe pas, et que les deux essayent d'insérer en même temps ? Vous avez une violation de contrainte unique dans une des deux sessions. Alors que vous avez justement écrit votre fonction dans l'espoir de l'éviter à votre utilisateur. Ce dernier point est un argument supplémentaire pour tenter d'insérer, puis intercepter l'erreur du violation de contrainte unique : votre code fonctionnera toujours, sans cas particulier à gérer.

Dernière modification par Marc Cousin (19/04/2010 14:03:22)


Marc.

Hors ligne

#3 19/04/2010 14:18:53

R.Seif
Membre

Re : optimisation de l'insertion et la selection

et pour l'index?
en fait le test que je vais essayer est énorme, pour des observations de 1 journée, il me faut une journée pour récupérer les résultats.
donc j'ai opté à éliminer les index puisqu'ils ne sont efficace qu'en lecture, et non pas en écriture.

Hors ligne

#4 19/04/2010 14:24:11

Marc Cousin
Membre

Re : optimisation de l'insertion et la selection

Les index sont efficaces en écriture justement quand la requête d'écriture a besoin de l'information , ce qui est le cas du select indiqué plus haut.

Pouvez vous poster la définition de la fonction host ?


Marc.

Hors ligne

#5 19/04/2010 14:42:41

R.Seif
Membre

Re : optimisation de l'insertion et la selection

et bah ça ne marche pas quand je fais l'insert avant le select.

Hors ligne

#6 19/04/2010 14:52:31

Marc Cousin
Membre

Re : optimisation de l'insertion et la selection

J'imagine, je ne suggérais pas de juste en inverser l'ordre d'exécution. Si vous faites l'insert alors que la donnée existe déjà, vous allez générer une erreur, qu'il faudra alors intercepter.

Je vous conseille de regarder http://docs.postgresql.fr/8.4/plpgsql-c … tures.html (paragraphe 8.6.5 et suivant), avant de continuer la discussion, le paragraphe devrait vous éclairer sur le sujet. La condition d'erreur à tester est "unique_violation".


Marc.

Hors ligne

#7 19/04/2010 15:52:06

R.Seif
Membre

Re : optimisation de l'insertion et la selection

c fait.
en plus j'ai gagné trop au niveau comparaison puisque mon prog utilise 5 fois la fonction mape_get_ip.
Je vous remercie.
smile

Dernière modification par R.Seif (19/04/2010 15:52:26)

Hors ligne

#8 19/04/2010 16:04:43

Marc Cousin
Membre

Re : optimisation de l'insertion et la selection

N'oubliez pas malgré tout cette problématique d'index sur mape_get_ip. C'est là qu'on va pouvoir obtenir le plus gros gain. Que fait la fonction host ?


Marc.

Hors ligne

#9 19/04/2010 16:16:44

R.Seif
Membre

Re : optimisation de l'insertion et la selection

wé je l'ai fixé.
host fait l'extraction de l'@ IP en texte.
càd    host('192.168.1.1') --> 192.168.1.1

pardon j'ai pa fé attention, mé vous voulez dire que l'index sur mape_add_ip n'est ce pa?
parce que j'ai pas fait d'index en mape_get_ip

Dernière modification par R.Seif (19/04/2010 16:19:09)

Hors ligne

#10 19/04/2010 16:28:26

Marc Cousin
Membre

Re : optimisation de l'insertion et la selection

Le problème est sur cet ordre :
SELECT INTO ipid ip FROM ips WHERE host(ips.ip) = host(addr)
Ce que vous demandez au moteur c'est de trouver tous les enregistrements de la table ipid qui vérifient  host(ips.ip) = host(addr)
Cela veut dire lire toute la table, et pour tous les enregistrements de la table, calculer host(ips.ip). Cela a deux conséquences :
- Beaucoup de calculs inutiles
- Impossible de trouver directement le bon enregistrement : même si vous avez un index sur la colonne ip, il est inutilisable, du fait de cette fonction.


Marc.

Hors ligne

Pied de page des forums