Bonjour,
Je dois afficher dans un CListCtrl, le resultat d'une requete SQL sur une
table très volumineuse (environ 1 000 000 de records). Pour l'affichage je
me débrouille avec un List ctrl virtuel. Ainsi, je n'ai pas à stocker en
mémoire le résultat de la requête, une fois le RecSet retourné l'affichage
est instantané quelque soit sa taille, et l'on peut naviguer de façon fluide
avec l'ascenseur.
Le soucis est le temps passé à attendre que le SQLEXECUTE retourne le record
set. Une solution serait d'organiser la base de données de façon à pouvoir
passer une requête du type "retourne moi les 1000 premiers puis les 1000
suivants, etc". Mais je ne vois pas comment faire. J'utilise ODBC et je dois
trouver une solution qui ne soit pas dépendante du type de la base (ORACLE,
MYSQL, DB, ...).
Cette action est irreversible, confirmez la suppression du commentaire ?
Signaler le commentaire
Veuillez sélectionner un problème
Nudité
Violence
Harcèlement
Fraude
Vente illégale
Discours haineux
Terrorisme
Autre
Christian
Vois de plus près le type de fetch et de curseur (Server-Side Cursors par exemple).
spi wrote:
Bonjour, Mais je ne vois pas comment faire. J'utilise ODBC et je dois trouver une solution qui ne soit pas dépendante du type de la base (ORACLE, MYSQL, DB, ...).
Vois de plus près le type de fetch et de curseur (Server-Side Cursors par
exemple).
spi wrote:
Bonjour,
Mais je ne vois pas comment
faire. J'utilise ODBC et je dois trouver une solution qui ne soit pas
dépendante du type de la base (ORACLE, MYSQL, DB, ...).
Vois de plus près le type de fetch et de curseur (Server-Side Cursors par exemple).
spi wrote:
Bonjour, Mais je ne vois pas comment faire. J'utilise ODBC et je dois trouver une solution qui ne soit pas dépendante du type de la base (ORACLE, MYSQL, DB, ...).
adebaene
"spi" wrote in message news:<418a7dd6$0$18482$...
Bonjour, Je dois afficher dans un CListCtrl, le resultat d'une requete SQL sur une table très volumineuse (environ 1 000 000 de records). Pour l'affichage je me débrouille avec un List ctrl virtuel. Ainsi, je n'ai pas à stocker en mémoire le résultat de la requête, une fois le RecSet retourné l'affichage est instantané quelque soit sa taille, et l'on peut naviguer de façon fluide avec l'ascenseur. Le soucis est le temps passé à attendre que le SQLEXECUTE retourne le record set. Une solution serait d'organiser la base de données de façon à pouvoir passer une requête du type "retourne moi les 1000 premiers puis les 1000 suivants, etc". Mais je ne vois pas comment faire. J'utilise ODBC et je dois trouver une solution qui ne soit pas dépendante du type de la base (ORACLE, MYSQL, DB, ...).
Si tu as un identifiant unique et s'incrémentant régulièrement dans ta table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0; int index_increment00;
while (donnes_a_lire) { ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE ..... ORDER BY Id WHERE Id>current_index" current_index=ResultSet[ResultSet.NumberOfRows].Id;
//faire quelque chose avec le ResultSet partiel }
Arnaud
"spi" <nomail@nospam.fr> wrote in message news:<418a7dd6$0$18482$8fcfb975@news.wanadoo.fr>...
Bonjour,
Je dois afficher dans un CListCtrl, le resultat d'une requete SQL sur une
table très volumineuse (environ 1 000 000 de records). Pour l'affichage je
me débrouille avec un List ctrl virtuel. Ainsi, je n'ai pas à stocker en
mémoire le résultat de la requête, une fois le RecSet retourné l'affichage
est instantané quelque soit sa taille, et l'on peut naviguer de façon fluide
avec l'ascenseur.
Le soucis est le temps passé à attendre que le SQLEXECUTE retourne le record
set. Une solution serait d'organiser la base de données de façon à pouvoir
passer une requête du type "retourne moi les 1000 premiers puis les 1000
suivants, etc". Mais je ne vois pas comment faire. J'utilise ODBC et je dois
trouver une solution qui ne soit pas dépendante du type de la base (ORACLE,
MYSQL, DB, ...).
Si tu as un identifiant unique et s'incrémentant régulièrement dans ta
table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0;
int index_increment00;
while (donnes_a_lire)
{
ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE .....
ORDER BY Id WHERE Id>current_index"
current_index=ResultSet[ResultSet.NumberOfRows].Id;
Bonjour, Je dois afficher dans un CListCtrl, le resultat d'une requete SQL sur une table très volumineuse (environ 1 000 000 de records). Pour l'affichage je me débrouille avec un List ctrl virtuel. Ainsi, je n'ai pas à stocker en mémoire le résultat de la requête, une fois le RecSet retourné l'affichage est instantané quelque soit sa taille, et l'on peut naviguer de façon fluide avec l'ascenseur. Le soucis est le temps passé à attendre que le SQLEXECUTE retourne le record set. Une solution serait d'organiser la base de données de façon à pouvoir passer une requête du type "retourne moi les 1000 premiers puis les 1000 suivants, etc". Mais je ne vois pas comment faire. J'utilise ODBC et je dois trouver une solution qui ne soit pas dépendante du type de la base (ORACLE, MYSQL, DB, ...).
Si tu as un identifiant unique et s'incrémentant régulièrement dans ta table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0; int index_increment00;
while (donnes_a_lire) { ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE ..... ORDER BY Id WHERE Id>current_index" current_index=ResultSet[ResultSet.NumberOfRows].Id;
//faire quelque chose avec le ResultSet partiel }
Arnaud
spi
Mon problème ne se pose pas au niveau du cursor, une fois que j'ai le recordset, je n'ai pas de soucis pour l'afficher dans le listCtrl virtuel. C'est de passer la requete qui me pose un problème, c'est le SQLEXECUTE que je trouve trop long.
"Christian" a écrit dans le message de news:418afea6$0$32143$
Vois de plus près le type de fetch et de curseur (Server-Side Cursors par exemple).
spi wrote: > Bonjour, > Mais je ne vois pas comment > faire. J'utilise ODBC et je dois trouver une solution qui ne soit pas > dépendante du type de la base (ORACLE, MYSQL, DB, ...).
Mon problème ne se pose pas au niveau du cursor, une fois que j'ai le
recordset, je n'ai pas de soucis pour l'afficher dans le listCtrl virtuel.
C'est de passer la requete qui me pose un problème, c'est le SQLEXECUTE que
je trouve trop long.
"Christian" <christnw-a-virer@free.fr> a écrit dans le message de
news:418afea6$0$32143$636a15ce@news.free.fr...
Vois de plus près le type de fetch et de curseur (Server-Side Cursors par
exemple).
spi wrote:
> Bonjour,
> Mais je ne vois pas comment
> faire. J'utilise ODBC et je dois trouver une solution qui ne soit pas
> dépendante du type de la base (ORACLE, MYSQL, DB, ...).
Mon problème ne se pose pas au niveau du cursor, une fois que j'ai le recordset, je n'ai pas de soucis pour l'afficher dans le listCtrl virtuel. C'est de passer la requete qui me pose un problème, c'est le SQLEXECUTE que je trouve trop long.
"Christian" a écrit dans le message de news:418afea6$0$32143$
Vois de plus près le type de fetch et de curseur (Server-Side Cursors par exemple).
spi wrote: > Bonjour, > Mais je ne vois pas comment > faire. J'utilise ODBC et je dois trouver une solution qui ne soit pas > dépendante du type de la base (ORACLE, MYSQL, DB, ...).
spi
> Si tu as un identifiant unique et s'incrémentant régulièrement dans ta table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0; int index_increment00;
while (donnes_a_lire) { ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE ..... ORDER BY Id WHERE Id>current_index" current_index=ResultSet[ResultSet.NumberOfRows].Id;
//faire quelque chose avec le ResultSet partiel }
Malheureusement, des records sont susceptibles d'être supprimés. Mais peut être effectivement que la solution serait de faire une colonne de numérotation, et de ne pas supprimer les records en cours de journée, juste les marquer pour deletion et que ce soit un agent qui se déclenche la nuit pour effacer les rangées marquées et renuméroter correctement.
> Si tu as un identifiant unique et s'incrémentant régulièrement dans ta
table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0;
int index_increment00;
while (donnes_a_lire)
{
ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE .....
ORDER BY Id WHERE Id>current_index"
current_index=ResultSet[ResultSet.NumberOfRows].Id;
//faire quelque chose avec le ResultSet partiel
}
Malheureusement, des records sont susceptibles d'être supprimés.
Mais peut être effectivement que la solution serait de faire une colonne de
numérotation, et de ne pas supprimer les records en cours de journée, juste
les marquer pour deletion et que ce soit un agent qui se déclenche la nuit
pour effacer les rangées marquées et renuméroter correctement.
> Si tu as un identifiant unique et s'incrémentant régulièrement dans ta table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0; int index_increment00;
while (donnes_a_lire) { ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE ..... ORDER BY Id WHERE Id>current_index" current_index=ResultSet[ResultSet.NumberOfRows].Id;
//faire quelque chose avec le ResultSet partiel }
Malheureusement, des records sont susceptibles d'être supprimés. Mais peut être effectivement que la solution serait de faire une colonne de numérotation, et de ne pas supprimer les records en cours de journée, juste les marquer pour deletion et que ce soit un agent qui se déclenche la nuit pour effacer les rangées marquées et renuméroter correctement.
spi
J'ai une autre question à ce sujet, je ne connais pas très bien les bases de données est la réponse est surement évidente. Mais si je crée une colonne avec une numérotation dans ma table a 1000 000 de lignes, et que j'indexe la table selon cette colonne. Lorque que je passerai une requête du type,
SELECT * FROM ma_table WHERE COMPT > 999 AND COMPT < 2000
est - ce que j'attenderai le même temps que si ma table avait juste 1000 lignes ? . "Arnaud Debaene" a écrit dans le message de news:
"spi" wrote in message
news:<418a7dd6$0$18482$...
> Bonjour, > Je dois afficher dans un CListCtrl, le resultat d'une requete SQL sur
une
> table très volumineuse (environ 1 000 000 de records). Pour l'affichage
je
> me débrouille avec un List ctrl virtuel. Ainsi, je n'ai pas à stocker
en
> mémoire le résultat de la requête, une fois le RecSet retourné
l'affichage
> est instantané quelque soit sa taille, et l'on peut naviguer de façon
fluide
> avec l'ascenseur. > Le soucis est le temps passé à attendre que le SQLEXECUTE retourne le
record
> set. Une solution serait d'organiser la base de données de façon à
pouvoir
> passer une requête du type "retourne moi les 1000 premiers puis les 1000 > suivants, etc". Mais je ne vois pas comment faire. J'utilise ODBC et je
dois
> trouver une solution qui ne soit pas dépendante du type de la base
(ORACLE,
> MYSQL, DB, ...).
Si tu as un identifiant unique et s'incrémentant régulièrement dans ta table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0; int index_increment00;
while (donnes_a_lire) { ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE ..... ORDER BY Id WHERE Id>current_index" current_index=ResultSet[ResultSet.NumberOfRows].Id;
//faire quelque chose avec le ResultSet partiel }
Arnaud
J'ai une autre question à ce sujet, je ne connais pas très bien les bases de
données est la réponse est surement évidente. Mais si je crée une colonne
avec une numérotation dans ma table a 1000 000 de lignes, et que j'indexe la
table selon cette colonne. Lorque que je passerai une requête du type,
SELECT * FROM ma_table WHERE COMPT > 999 AND COMPT < 2000
est - ce que j'attenderai le même temps que si ma table avait juste 1000
lignes ?
.
"Arnaud Debaene" <adebaene@club-internet.fr> a écrit dans le message de
news:16a4a8c7.0411050458.59412454@posting.google.com...
> Bonjour,
> Je dois afficher dans un CListCtrl, le resultat d'une requete SQL sur
une
> table très volumineuse (environ 1 000 000 de records). Pour l'affichage
je
> me débrouille avec un List ctrl virtuel. Ainsi, je n'ai pas à stocker
en
> mémoire le résultat de la requête, une fois le RecSet retourné
l'affichage
> est instantané quelque soit sa taille, et l'on peut naviguer de façon
fluide
> avec l'ascenseur.
> Le soucis est le temps passé à attendre que le SQLEXECUTE retourne le
record
> set. Une solution serait d'organiser la base de données de façon à
pouvoir
> passer une requête du type "retourne moi les 1000 premiers puis les 1000
> suivants, etc". Mais je ne vois pas comment faire. J'utilise ODBC et je
dois
> trouver une solution qui ne soit pas dépendante du type de la base
(ORACLE,
> MYSQL, DB, ...).
Si tu as un identifiant unique et s'incrémentant régulièrement dans ta
table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0;
int index_increment00;
while (donnes_a_lire)
{
ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE .....
ORDER BY Id WHERE Id>current_index"
current_index=ResultSet[ResultSet.NumberOfRows].Id;
J'ai une autre question à ce sujet, je ne connais pas très bien les bases de données est la réponse est surement évidente. Mais si je crée une colonne avec une numérotation dans ma table a 1000 000 de lignes, et que j'indexe la table selon cette colonne. Lorque que je passerai une requête du type,
SELECT * FROM ma_table WHERE COMPT > 999 AND COMPT < 2000
est - ce que j'attenderai le même temps que si ma table avait juste 1000 lignes ? . "Arnaud Debaene" a écrit dans le message de news:
"spi" wrote in message
news:<418a7dd6$0$18482$...
> Bonjour, > Je dois afficher dans un CListCtrl, le resultat d'une requete SQL sur
une
> table très volumineuse (environ 1 000 000 de records). Pour l'affichage
je
> me débrouille avec un List ctrl virtuel. Ainsi, je n'ai pas à stocker
en
> mémoire le résultat de la requête, une fois le RecSet retourné
l'affichage
> est instantané quelque soit sa taille, et l'on peut naviguer de façon
fluide
> avec l'ascenseur. > Le soucis est le temps passé à attendre que le SQLEXECUTE retourne le
record
> set. Une solution serait d'organiser la base de données de façon à
pouvoir
> passer une requête du type "retourne moi les 1000 premiers puis les 1000 > suivants, etc". Mais je ne vois pas comment faire. J'utilise ODBC et je
dois
> trouver une solution qui ne soit pas dépendante du type de la base
(ORACLE,
> MYSQL, DB, ...).
Si tu as un identifiant unique et s'incrémentant régulièrement dans ta table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
int current_index=0; int index_increment00;
while (donnes_a_lire) { ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE ..... ORDER BY Id WHERE Id>current_index" current_index=ResultSet[ResultSet.NumberOfRows].Id;
//faire quelque chose avec le ResultSet partiel }
Arnaud
Christian
Au niveau du moteur de base existe la notion d'optmisateur (opération très importante effectuée par le serveur qui détermine les opérations élémentaires d'accès demandées par le SELECT)..
L'optmisateur construit un plan (selon les index, le hash, etc) et aussi selon les statistiques de répartitions qui lui permettent d'évaleur le nb de rows ayant certaines caractéristiques).
Parfois les jointures sont telles qu'ils décide de construire au préalable une ou plusieurs "tables" intermédaires, dans ce cas le SELECT est très long même s'il retourne une petite table. Chaque SGBD a sa propre méthode ... La portabilité est pleine de surprise et on passe du temps à ça je dois te dire.
La solution par le type de curseur (qui ne se résume pas au pointeur des Record Set client) est donc à regarder de près et peut être sans avoir à scinder "à la main" avec des LIMIT (le temps de réponse dépend du "plan" et de la conservation des tables intermédiares -s'il y en a- et de la manière d'accéder à la Nème row) ou des WHERE (idem).
Le cas le plus simple SELECT * FROM ORDER BY (sans WHERE) est un plan indexé si l'index existe. Si l'index n'existe pas (ce qui serait une erreur de design), l'optmsateur construit des données intermédaires et c'est long quoi qu'on fasse.
Emal moi si tu veux, ce soir ou demain je pourrais te donner plus de précision.
Au niveau du moteur de base existe la notion d'optmisateur (opération très
importante effectuée par le serveur qui détermine les opérations
élémentaires d'accès demandées par le SELECT)..
L'optmisateur construit un plan (selon les index, le hash, etc) et aussi
selon les statistiques de répartitions qui lui permettent d'évaleur le nb de
rows ayant certaines caractéristiques).
Parfois les jointures sont telles qu'ils décide de construire au préalable
une ou plusieurs "tables" intermédaires, dans ce cas le SELECT est très long
même s'il retourne une petite table. Chaque SGBD a sa propre méthode ... La
portabilité est pleine de surprise et on passe du temps à ça je dois te
dire.
La solution par le type de curseur (qui ne se résume pas au pointeur des
Record Set client) est donc à regarder de près et peut être sans avoir à
scinder "à la main" avec des LIMIT (le temps de réponse dépend du "plan" et
de la conservation des tables intermédiares -s'il y en a- et de la manière
d'accéder à la Nème row) ou des WHERE (idem).
Le cas le plus simple SELECT * FROM ORDER BY (sans WHERE) est un plan indexé
si l'index existe. Si l'index n'existe pas (ce qui serait une erreur de
design), l'optmsateur construit des données intermédaires et c'est long quoi
qu'on fasse.
Emal moi si tu veux, ce soir ou demain je pourrais te donner plus de
précision.
Au niveau du moteur de base existe la notion d'optmisateur (opération très importante effectuée par le serveur qui détermine les opérations élémentaires d'accès demandées par le SELECT)..
L'optmisateur construit un plan (selon les index, le hash, etc) et aussi selon les statistiques de répartitions qui lui permettent d'évaleur le nb de rows ayant certaines caractéristiques).
Parfois les jointures sont telles qu'ils décide de construire au préalable une ou plusieurs "tables" intermédaires, dans ce cas le SELECT est très long même s'il retourne une petite table. Chaque SGBD a sa propre méthode ... La portabilité est pleine de surprise et on passe du temps à ça je dois te dire.
La solution par le type de curseur (qui ne se résume pas au pointeur des Record Set client) est donc à regarder de près et peut être sans avoir à scinder "à la main" avec des LIMIT (le temps de réponse dépend du "plan" et de la conservation des tables intermédiares -s'il y en a- et de la manière d'accéder à la Nème row) ou des WHERE (idem).
Le cas le plus simple SELECT * FROM ORDER BY (sans WHERE) est un plan indexé si l'index existe. Si l'index n'existe pas (ce qui serait une erreur de design), l'optmsateur construit des données intermédaires et c'est long quoi qu'on fasse.
Emal moi si tu veux, ce soir ou demain je pourrais te donner plus de précision.
Christian
Au niveau du moteur de base existe la notion d'optmisateur (opération très importante effectuée par le serveur qui détermine les opérations élémentaires d'accès demandées par le SELECT)..
L'optmisateur construit un plan (selon les index, etc) et aussi parois selon les statistiques de répartitions qui lui permettent d'évaleur le nb de rows ayant certaines caractéristiques). Certains SGBD ont des foreign key avec index inclus d'autre pas et ça évlue sans cesse avec les versions qui se succèdent... C'est malheursement difficile de faire un truc portable.
Lorsque les jointures sont telles que l'optmisateur décide de construire au préalable une ou plusieurs "tables" intermédaires, dans ce cas le SELECT est très long même s'il retourne une petite table.
Chaque SGBD a sa propre méthode ... La portabilité est pleine de surprise et on passe du temps à ça je dois te dire.
La solution par le type de curseur (qui ne se résume pas au pointeur des Record Set client) est donc à regarder de près et peut être sans avoir à scinder "à la main" avec des LIMIT (le temps de réponse dépend du "plan" et de la conservation des tables intermédiares -s'il y en a- et de la manière d'accéder à la Nème row) ou des WHERE (idem).
Le cas le plus simple SELECT * FROM ORDER BY (sans WHERE) est un plan indexé si l'index existe. Si l'index n'existe pas (ce qui serait une erreur de design), l'optmsateur construit des données intermédaires et c'est long quoi qu'on fasse.
Emal moi () je pourrais te donner plus de précision.
Au niveau du moteur de base existe la notion d'optmisateur (opération très
importante effectuée par le serveur qui détermine les opérations
élémentaires d'accès demandées par le SELECT)..
L'optmisateur construit un plan (selon les index, etc) et aussi
parois selon les statistiques de répartitions qui lui permettent d'évaleur
le nb de
rows ayant certaines caractéristiques). Certains SGBD ont des foreign key
avec index inclus d'autre pas et ça évlue sans cesse avec les versions qui
se succèdent... C'est malheursement difficile de faire un truc portable.
Lorsque les jointures sont telles que l'optmisateur décide de construire au
préalable
une ou plusieurs "tables" intermédaires, dans ce cas le SELECT est très long
même s'il retourne une petite table.
Chaque SGBD a sa propre méthode ... La portabilité est pleine de surprise et
on passe du temps à ça je dois te dire.
La solution par le type de curseur (qui ne se résume pas au pointeur des
Record Set client) est donc à regarder de près et peut être sans avoir à
scinder "à la main" avec des LIMIT (le temps de réponse dépend du "plan" et
de la conservation des tables intermédiares -s'il y en a- et de la manière
d'accéder à la Nème row) ou des WHERE (idem).
Le cas le plus simple SELECT * FROM ORDER BY (sans WHERE) est un plan indexé
si l'index existe. Si l'index n'existe pas (ce qui serait une erreur de
design), l'optmsateur construit des données intermédaires et c'est long quoi
qu'on fasse.
Emal moi (christnw-a-virer@free.fr) je pourrais te donner plus de précision.
Au niveau du moteur de base existe la notion d'optmisateur (opération très importante effectuée par le serveur qui détermine les opérations élémentaires d'accès demandées par le SELECT)..
L'optmisateur construit un plan (selon les index, etc) et aussi parois selon les statistiques de répartitions qui lui permettent d'évaleur le nb de rows ayant certaines caractéristiques). Certains SGBD ont des foreign key avec index inclus d'autre pas et ça évlue sans cesse avec les versions qui se succèdent... C'est malheursement difficile de faire un truc portable.
Lorsque les jointures sont telles que l'optmisateur décide de construire au préalable une ou plusieurs "tables" intermédaires, dans ce cas le SELECT est très long même s'il retourne une petite table.
Chaque SGBD a sa propre méthode ... La portabilité est pleine de surprise et on passe du temps à ça je dois te dire.
La solution par le type de curseur (qui ne se résume pas au pointeur des Record Set client) est donc à regarder de près et peut être sans avoir à scinder "à la main" avec des LIMIT (le temps de réponse dépend du "plan" et de la conservation des tables intermédiares -s'il y en a- et de la manière d'accéder à la Nème row) ou des WHERE (idem).
Le cas le plus simple SELECT * FROM ORDER BY (sans WHERE) est un plan indexé si l'index existe. Si l'index n'existe pas (ce qui serait une erreur de design), l'optmsateur construit des données intermédaires et c'est long quoi qu'on fasse.
Emal moi () je pourrais te donner plus de précision.
Christian
Sous ORACLE les curseurs de base sur serveur ne lisent pas tout le SELECT avant de rendre la main ! Ton cas est tout ce qu'il y a de classique et on ne s'enquiquine pas à décomposer le SELECT. On ouvre un curseur OPEN / LOOP / CLOSE.
Les environnement comme ADO ou PowerBuilder crée des objets +- graphiques à "curseur client" sous forme de données rapatriées sur le client qu'on accède ensuite par un next/prior local (sans accès serveur), mais dans ce cas le SELECT complet est lu. Si ton SELECT renvoie un million de lignes et bien elles seront alors intégralement lues.
C'est pourquoi en ADO connecté sur ORACLE (test en VB6) il y a une option sur la "connexion" "cursor location" soit "curseur serveur" qui accède par "curseur base" vrai. Je viens de vérifier dans ma table d'essai de un million de lignes : si on choisit dans la "connexion" un curseur de type "adUseClient", tous est lu et l'affichage de la 1ère ligne apparait ensuite, si on choisit "adUseServer", l'affichage de la 1ère row (ou des N 1ère row) est immédiat, le "rs.moveNext" aussi.
*Remarque* : Attention, le SELECT est une opération très compliquée en interne d'un SGBD ! Lorsqu'il reçoit un SELECT, un "optimisateur" (optimizer) cherche en 1er lieu le meilleur chemin d'accès, il analyse le schéma de la base et parfois évaluent les statistiques des contenus. S'il y a des jointures entre table, il regarde comment elles seront le plus rapidement effectuées. Parfois des données temporaires seront construites au préalable. Par exemple un "OPEN curseur" sur SELECT * FROM A ORDER BY I, est immédiat si il y a un INDEX sur I mais demandera un balayage préalable (Full table scan) s'il n'y en a pas car le serveur ne connait pas la 1ère ligne classée selon I. Donc regarde si ton SELECT est bien adapté à ton schéma.
Lorsqu'on travaille sur des système multi-bases, le "plan" obtenu par leur optimisateur respectif peut différer énormément si le SELECT sont un tant soit peu compliqué. On a des temps de réponses qui varie de immédiat à ... très long. Il faut essayer et les surprises sont de taille. Si ton SELECT est simple, c'est identique.
si tu veux plus de renseignements tu peux me contacter
spi wrote:
Mon problème ne se pose pas au niveau du cursor, une fois que j'ai le recordset, je n'ai pas de soucis pour l'afficher dans le listCtrl virtuel. C'est de passer la requete qui me pose un problème, c'est le SQLEXECUTE que je trouve trop long.
Sous ORACLE les curseurs de base sur serveur ne lisent pas tout le SELECT
avant de rendre la main ! Ton cas est tout ce qu'il y a de classique et on
ne s'enquiquine pas à décomposer le SELECT. On ouvre un curseur OPEN / LOOP
/ CLOSE.
Les environnement comme ADO ou PowerBuilder crée des objets +- graphiques à
"curseur client" sous forme de données rapatriées sur le client qu'on accède
ensuite par un next/prior local (sans accès serveur), mais dans ce cas le
SELECT complet est lu. Si ton SELECT renvoie un million de lignes et bien
elles seront alors intégralement lues.
C'est pourquoi en ADO connecté sur ORACLE (test en VB6) il y a une option
sur la "connexion" "cursor location" soit "curseur serveur" qui accède par
"curseur base" vrai. Je viens de vérifier dans ma table d'essai de un
million de lignes : si on choisit dans la "connexion" un curseur de type
"adUseClient", tous est lu et l'affichage de la 1ère ligne apparait ensuite,
si on choisit "adUseServer", l'affichage de la 1ère row (ou des N 1ère row)
est immédiat, le "rs.moveNext" aussi.
*Remarque* : Attention, le SELECT est une opération très compliquée en
interne d'un SGBD ! Lorsqu'il reçoit un SELECT, un "optimisateur"
(optimizer) cherche en 1er lieu le meilleur chemin d'accès, il analyse le
schéma de la base et parfois évaluent les statistiques des contenus. S'il y
a des jointures entre table, il regarde comment elles seront le plus
rapidement effectuées. Parfois des données temporaires seront construites au
préalable. Par exemple un "OPEN curseur" sur SELECT * FROM A ORDER BY I, est
immédiat si il y a un INDEX sur I mais demandera un balayage préalable (Full
table scan) s'il n'y en a pas car le serveur ne connait pas la 1ère ligne
classée selon I. Donc regarde si ton SELECT est bien adapté à ton schéma.
Lorsqu'on travaille sur des système multi-bases, le "plan" obtenu par leur
optimisateur respectif peut différer énormément si le SELECT sont un tant
soit peu compliqué. On a des temps de réponses qui varie de immédiat à ...
très long. Il faut essayer et les surprises sont de taille. Si ton SELECT
est simple, c'est identique.
si tu veux plus de renseignements tu peux me contacter
christnw-a-virer@free.fr
spi wrote:
Mon problème ne se pose pas au niveau du cursor, une fois que j'ai le
recordset, je n'ai pas de soucis pour l'afficher dans le listCtrl
virtuel. C'est de passer la requete qui me pose un problème, c'est le
SQLEXECUTE que je trouve trop long.
Sous ORACLE les curseurs de base sur serveur ne lisent pas tout le SELECT avant de rendre la main ! Ton cas est tout ce qu'il y a de classique et on ne s'enquiquine pas à décomposer le SELECT. On ouvre un curseur OPEN / LOOP / CLOSE.
Les environnement comme ADO ou PowerBuilder crée des objets +- graphiques à "curseur client" sous forme de données rapatriées sur le client qu'on accède ensuite par un next/prior local (sans accès serveur), mais dans ce cas le SELECT complet est lu. Si ton SELECT renvoie un million de lignes et bien elles seront alors intégralement lues.
C'est pourquoi en ADO connecté sur ORACLE (test en VB6) il y a une option sur la "connexion" "cursor location" soit "curseur serveur" qui accède par "curseur base" vrai. Je viens de vérifier dans ma table d'essai de un million de lignes : si on choisit dans la "connexion" un curseur de type "adUseClient", tous est lu et l'affichage de la 1ère ligne apparait ensuite, si on choisit "adUseServer", l'affichage de la 1ère row (ou des N 1ère row) est immédiat, le "rs.moveNext" aussi.
*Remarque* : Attention, le SELECT est une opération très compliquée en interne d'un SGBD ! Lorsqu'il reçoit un SELECT, un "optimisateur" (optimizer) cherche en 1er lieu le meilleur chemin d'accès, il analyse le schéma de la base et parfois évaluent les statistiques des contenus. S'il y a des jointures entre table, il regarde comment elles seront le plus rapidement effectuées. Parfois des données temporaires seront construites au préalable. Par exemple un "OPEN curseur" sur SELECT * FROM A ORDER BY I, est immédiat si il y a un INDEX sur I mais demandera un balayage préalable (Full table scan) s'il n'y en a pas car le serveur ne connait pas la 1ère ligne classée selon I. Donc regarde si ton SELECT est bien adapté à ton schéma.
Lorsqu'on travaille sur des système multi-bases, le "plan" obtenu par leur optimisateur respectif peut différer énormément si le SELECT sont un tant soit peu compliqué. On a des temps de réponses qui varie de immédiat à ... très long. Il faut essayer et les surprises sont de taille. Si ton SELECT est simple, c'est identique.
si tu veux plus de renseignements tu peux me contacter
spi wrote:
Mon problème ne se pose pas au niveau du cursor, une fois que j'ai le recordset, je n'ai pas de soucis pour l'afficher dans le listCtrl virtuel. C'est de passer la requete qui me pose un problème, c'est le SQLEXECUTE que je trouve trop long.
adebaene
"spi" wrote in message news:<418caeca$0$18525$...
> Si tu as un identifiant unique et s'incrémentant régulièrement dans ta > table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code : > > int current_index=0; > int index_increment00; > > while (donnes_a_lire) > { > ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE ..... > ORDER BY Id WHERE Id>current_index" > current_index=ResultSet[ResultSet.NumberOfRows].Id; > > //faire quelque chose avec le ResultSet partiel > } >
Malheureusement, des records sont susceptibles d'être supprimés.
Et alors? La solution que je propose récupère la valeur maximale de "index" renvoyée par le ResultSet partiel et l'utilise pour savoir où commencer la requête suivante. Même s'il y a des "trous" dans la colonne Index, ca n'a pas d'incidence. (le truc, c'est que curent_index est incrémenté *d'au moins" 1000 à chaque itération, plus s'il y a des trous dans la colonne index).
Au fait, pour bien faire il faudrait initialiser current_index à -1 au début...
Mais peut être effectivement que la solution serait de faire une colonne de numérotation, et de ne pas supprimer les records en cours de journée, juste les marquer pour deletion et que ce soit un agent qui se déclenche la nuit pour effacer les rangées marquées et renuméroter correctement.
Pourquoi faire une usine à gaz pour si peu?
Arnaud MVP - VC
"spi" <nomail@nospam.fr> wrote in message news:<418caeca$0$18525$8fcfb975@news.wanadoo.fr>...
> Si tu as un identifiant unique et s'incrémentant régulièrement dans ta
> table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code :
>
> int current_index=0;
> int index_increment00;
>
> while (donnes_a_lire)
> {
> ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE .....
> ORDER BY Id WHERE Id>current_index"
> current_index=ResultSet[ResultSet.NumberOfRows].Id;
>
> //faire quelque chose avec le ResultSet partiel
> }
>
Malheureusement, des records sont susceptibles d'être supprimés.
Et alors? La solution que je propose récupère la valeur maximale de
"index" renvoyée par le ResultSet partiel et l'utilise pour savoir où
commencer la requête suivante. Même s'il y a des "trous" dans la
colonne Index, ca n'a pas d'incidence. (le truc, c'est que
curent_index est incrémenté *d'au moins" 1000 à chaque itération, plus
s'il y a des trous dans la colonne index).
Au fait, pour bien faire il faudrait initialiser current_index à -1 au
début...
Mais peut être effectivement que la solution serait de faire une colonne de
numérotation, et de ne pas supprimer les records en cours de journée, juste
les marquer pour deletion et que ce soit un agent qui se déclenche la nuit
pour effacer les rangées marquées et renuméroter correctement.
> Si tu as un identifiant unique et s'incrémentant régulièrement dans ta > table (une colonne ID typiquement), tu peux l'utiliser : Pseudo code : > > int current_index=0; > int index_increment00; > > while (donnes_a_lire) > { > ResultSet="SELECT TOP <index_increment> * FROM MaTable WHERE ..... > ORDER BY Id WHERE Id>current_index" > current_index=ResultSet[ResultSet.NumberOfRows].Id; > > //faire quelque chose avec le ResultSet partiel > } >
Malheureusement, des records sont susceptibles d'être supprimés.
Et alors? La solution que je propose récupère la valeur maximale de "index" renvoyée par le ResultSet partiel et l'utilise pour savoir où commencer la requête suivante. Même s'il y a des "trous" dans la colonne Index, ca n'a pas d'incidence. (le truc, c'est que curent_index est incrémenté *d'au moins" 1000 à chaque itération, plus s'il y a des trous dans la colonne index).
Au fait, pour bien faire il faudrait initialiser current_index à -1 au début...
Mais peut être effectivement que la solution serait de faire une colonne de numérotation, et de ne pas supprimer les records en cours de journée, juste les marquer pour deletion et que ce soit un agent qui se déclenche la nuit pour effacer les rangées marquées et renuméroter correctement.