2010-07-26 4 views
1

Je suis nouveau à ADO.net et ont ce problème:Comment revenir aussi peu que possible les lignes de la table liée

Supposons que j'ai ces deux tables dans une base de données SQL Server 2005, avec ces colonnes:

[commandes]

  • OrderID
  • OrderDate
  • ShopID
  • TotalAmoun t
  • TotalTaxAmount
  • etc ...

[OrdersDetails]

  • OrderID
  • ShopID
  • ItemID
  • Quantité
  • Montant
  • TaxAmount
  • etc

J'ai commencé une application WinForms pour me commencer. Dans ce formulaire, l'utilisateur peut sélectionner une liste de magasins et sélectionner une plage de dates pour voir toutes les commandes de ce magasin.

J'ai ajouté une source de données à partir de Visual Studio, sélectionnez la table Orders et OrdersDetails et glissé et déposé les commandes et les tables OrdersDetails connexes dans le formulaire en tant que DataGridViews.

Lorsque je sélectionne une ligne à partir de la commande DataGridView, je vois effectivement les détails des commandes correspondantes dans le second DataGridView comme je le voulais. J'avais des relations à l'intérieur de cette base de données et ADO.net les a saisies et les a reflétées dans l'ensemble de données.

J'ai ensuite ajouté une méthode à mon jeu de données typé pour obtenir des données par les colonnes OrderDate et ShopID. Comme la table OrdersDetails n'a pas de colonne OrderDate, je n'ai pu la filtrer que par ShopID. Le problème est qu'il prend beaucoup de temps pour obtenir les enregistrements de OrdersDetails car il récupérera plus de lignes que nécessaire dans le DataTable pour OrdersDetails. Le problème est que je ne peux filtrer que les lignes de la table OrderDetails par ShopID, ce qui renvoie beaucoup trop d'enregistrements de la base de données.

De toute évidence, ADO.net est capable de les filtrer de manière appropriée sur le client en utilisant la relation OrderID, mais il serait beaucoup plus logique de récupérer uniquement les lignes de OrdersDetails dont j'ai réellement besoin. J'ai modifié mes requêtes en obtenant les données de la deuxième table pour ajouter le OrderDate en utilisant une jointure, ainsi je peux filtrer par date quand je récupère les données de la base de données ... cependant, cela pose des problèmes quand j'essaye de mettre à jour mes changements dus à cette colonne étrangère ...

Je crois qu'il doit y avoir un moyen facile de contourner ce problème, n'est-ce pas?

Merci beaucoup d'avance.

Répondre

2

que vous voulez faire quelque chose comme ça

SELECT * 
FROM OrderDetails 
WHERE 
    ShopID IN (@listOfShopIds) 
    AND 
    OrderID IN (
     SELECT OrderID 
     FROM Orders 
     WHERE 
      OrderDate BETWEEN @dateFrom AND @dateTo 
    ) 
+0

'OERE OrderID IN (SELECT ...)' peut facilement être converti en une jointure, ce qui serait beaucoup plus efficace. –

+0

@Winston Smith: il pourrait facilement être écrit comme une jointure interne, oui. en fait, c'est ainsi que le serveur sql fusionnera les résultats d'un select comme celui-ci. il utilisera les mêmes statistiques, élaborera le même plan d'exécution et fonctionnera aussi bien (puisqu'il fait exactement la même chose) dans les deux solutions. –

+0

Merci beaucoup. En fait, j'ai fait une jointure avant comme je l'ai dit dans la question, mais mon problème était que j'ai ajouté cette colonne à la table retournée qui a causé les problèmes avec les mises à jour. Votre réponse m'a fait réaliser mon erreur. Merci. –

0

@ David il est probablement préférable d'écrire du code qui exprime votre intention et reflète l'algorithme plus performant, plutôt que de compter sur les détails de mise en œuvre du moteur pour effectuer l'optimisation .

+0

euh, n'a pas remarqué celui-ci jusqu'à maintenant. Cependant, si vous écrivez votre requête sql, vous comptez sur le moteur pour l'exécuter de manière performante, en utilisant les index et les statistiques disponibles. Que vous l'exprimiez en jointure ou sous-requête, vous avez affaire à deux jeux d'enregistrements séparés qui seront fusionnés par le moteur en fonction d'un critère donné. les moyens par lesquels les deux ensembles sont fusionnés dans ces cas sont appelés * boucles imbriquées *. Les boucles imbriquées sont ce qui se passe à la fois dans la jointure et dans la sous-requête. dans la plupart des scénarios, son coût sera négligeable par rapport au filtrage des ... –

+0

deux sous-ensembles qui sont soumis à la fusion en premier lieu, mais qui est périphérique au point - le point clé étant que quel que soit son coût, il est le * même * dans les deux sens de l'écriture du code, parce que les deux façons * sont * les mêmes (dans ce contexte). donc il n'y a pas une façon qui soit plus performante, et il n'y a aucune des deux façons d'écrire la requête qui est plus proche que l'autre de dire "Hey SQL server, faire un index chercher sur cette table et un autre sur cette table , en utilisant l'index tel et tel, puis fusionner les deux ensembles en utilisant des boucles imbriquées dans un seul résultat ". nous avons simplement * avoir * à ... –

+0

compter sur le moteur pour comprendre cela. à la fin, tout est une question de préférence. et je pense sincèrement que "où l'identifiant de commande est l'identifiant de l'un des ordres dans cette période" exprime le résultat attendu * au moins * ainsi que toute jointure. –

Questions connexes