Forum Clubic

Optimisation SQL :: Selection de trois élements non-continus

Bonjour,

Je viens ici essayer de trouver une méthode efficace pour récupérer dans une table trois éléments qui se succèdent avec leur clé primaire, mais celle-ci n’est pas forcément continu. J’ai regardé rapidement sur le net, et les requêtes que j’ai pu trouver étaient soit une succession de requêtes, soit une requête avec une sous-requête.

Matable :

id | data

1 => data
3 => data
4 => data
6 => data

Imaginons que j’ai l’id4 à récupérer. J’aimerais qu’en une seule requête, la plus optimisé possible, récupérer l’id3 et l’id6 en plus de l’id4.
Comment faites-vous ce genre de requête?
Edité le 15/03/2008 à 13:08

Je ne crois pas avoir tout saisi au problème.

Tu veux récupérer les 2 (=3-1) enregistrements “autour” d’un enregistrement x ?

Effectivement je ne vois que deux requêtes SQL :

:-/

C’est moche… C’est le genre de méthode que j’applique mais j’apprécie pas du tout, je cherche un moyen de faire plus propre, m’enfin encore faut-il que ce soit possible.
Sinon oui tu as bien compris le problème.
Si on récapitule, avec ta méthode on passe déjà 3 requêtes, celle de champ en question, puis celle pour récupérer l’entrée précédente puis l’entrée suivante.

Un méthode déjà plus rapide consisterait à récupérer l’enregistrement précédent, et à partir de son id sélectionner les deux entrées qui le succède en plus d’elle même.

Requete n°1 :

SELECT id 
FROM matable
WHERE id < $mon_id
ORDER BY id ASC
LIMIT 1

Requete n°2 :

SELECT *
FROM matable
WHERE id > $id_de_la_requete_n°1
ORDER BY id ASC
LIMIT 3

Qu’est-ce qui est le plus rapide? Qu’est-ce qu’il y a de mieux?

Je préfère celle de Raynor…

Dans les 2 cas tu as 2 requêtes en plus, ça ne change pas grand chose.
Celle de Raynor est plus directe (sauf qu’il faudrait plutot un > strict non ? ) donc je préfère aussi.
Le sql et pas trop adapté à ce genre de truc, c’est plutôt de traitement par groupe avec des jointures exactes. mais mettre en relation des id comme ça… peut-être qu’il faut ajouter une table ou une vue d’association prec-suiv, à mettre à jour avec un trigger sur ta table.

la méthode bourrin:


Create view temp as 
(select id , ( select min(id) from table t2 where t2.id > t1.id) as suiv from table t1)

--- edit, si la syntaxe ne fonctionne pas, on est obligé de la faire en 2 parties
Create view temp as 
(select t1.id , t2.id as suiv from table t1, table t2 where
t2.id =  ( select min(id) from table2 where id > t1.id))
-- et ça rame bien...


select * from table t
inner join temp prec
on t.id = prec.id
inner join temp suiv
on t.id= suiv.suiv
where
[condition sur t]


est-ce que ça marcherais?

edit: par contre, c’est pas du tout optimal, j’ai lancé une requête analogue su notre serveur, et ça ramme grave :smiley:
Edité le 17/03/2008 à 14:58

J’ai mis un >= pour récupérer l’enregistrement d’ID 4 (et le 5).

Avec un “t” peut-être mieux :stuck_out_tongue: !
Je prends note, mais vu ton edit je vais pas retenir cette solution :/.

Après Raynor à raison, j’avais pas vu qu’avec le = on obtenait la valeur souhaitée en plus des autres. Je me suis pas trop penché sur le UNION, mais on y gagne quelque chose à lancer deux requêtes en UNION ou c’est juste plus jolie?

Comme ça, de prime abord, je dirais que l’UNION gagnerait en temps car en envoie une seule fois la requête, mais est-ce négligeable?

Il y a bien deux SELECT mais on peut penser que MySQL se servira de la réservation de ressources de la première requête lorsqu’il effectuera la seconde (vu qu’il sait qu’il y a un UNION entre la même table).

[:eveden]
tu ferais fureur sur DSA :paf:
ouais, j’ai nommé ma solution “bourrin” car justement, je ne la choisirait pas moi même.
avec une table au lieu d’une vue et un index par contre ça gagnerais, il faut voir si ça vaut le coup. (rajouter un trigger, j’ai jamais fait)

pour moi c’est peanuts, tu gagne le temps de latence d’un appel, mais le moteur SQL fait la même chose.
perso, je fais quasi jamais d’UNION ( en fait seulement si le programme d’appel (ou le CP) est psycho rigide et qu’il n’accepte qu’une seule requête)

DSA :confused: ?

Personnellement j’utilise mon propre moteur de gestion SQL en PHP, et n’ayant pas pris le temps je n’y ai pas implémenté la fonction UNION, enfin ce n’est pas le problème car je peux quand même la passer en désactivant l’analyse, mais est-ce qu’il vaille la peine que je consacre un peu de temps avec cette fonction? Je dérive du sujet initial, je m’en excuse.

Nan nan, c’est ton sujet, ne t’excuse pas de flooder dessus.
Tu as vraiment implémenté un moteur SQL :ouch:

Enfin peut-être j’utilise mal mes termes, mais j’ai fais un classe PHP5 qui gère toutes les requêtes de mes sites, je travaille encore dessus, donc elle est pas terminée, mais elle gère toutes mes requêtes en prenant comme paramètres des array().

Un exemple :

$MySql->Select('matable'); 

Ce qui retournera en SQL:

SELECT *
FROM 'matable'
LIMIT 0,30

Si erreur est détectée, avec ma classe de gestion d’erreur ça va bloquer toutes les prochaines exécutions de requêtes SQL dans mon script, ainsi que retourner un message d’erreur SQL avec une colorisation syntaxique et quelques infos qui sont stockées dans une table log de ma base de donnée comme l’ip de l’utilisateur, l’erreur SQL générée avec son code et le fichier où est appelée la requête etc…
Edité le 19/03/2008 à 14:25

Ah oui d’accord, c’est plus un framework métier, tu encapsule les requêtes SQL (un peu comme hibernate ou JPA en Java)
ça peut être une bonne idée,
moi j’ai cru que tu avais implémenté une grammaire SQL, avec un moteur derrière, ou une BD mais en transformant les requêtes à la volée.
(ça se fait, mais c’est long et pas très utile, donc pour tout dire ça me tente de le faire :smiley: )

Enfin dans un premier temps, je trouve que de simplement centraliser les requêtes, et éventuellement implémenter un petit cache dessus, c’est suffisant.

ensuite pour faire un framework à la Hibernate, il faut aussi générer les objets métiers… moi je ne trouve pas ça forcément très pratique.

Personnellement j’ai simplement fait un traitement de tableaux pour passer ma requête, avec les fonctions usuelles que j’ai l’habitude d’utiliser, et derrière un traitement totale rendant impossible l’injection. J’avais pensé à me faire ma propre base de donnée dans un certain contexte, ça viendra surement avec le temps, une DB totalement gérée en XML avec des possibilité d’exportation et de diffusion avancées, notamment pour un projet personnel de broadcast de DB. Mais là actuellement MySQL me suffit largement, ne l’utilisant que pour de simples requêtes.

ok,
c’est pas forcément utile de faire une BD en XML natif, y a déjà de quoi faire en restant en SQL standard, en paramétrant des urls de connexions vers différents BD.

Oui, certes, mais j’aimerais pouvoir exporter des updates de bases à travers des flux RSS, et puis j’ai toujours été intéressé par construire la propre branche qui me soutient :confused: !