web-dev-qa-db-fra.com

SQL Server - Performance liée au serveur et à la requête liées

J'ai un problème de performance lié aux serveurs/vues SQL Server/liés. J'espère que vous pourrez m'aider à comprendre quelle est la meilleure façon de faire ce que je veux =).

  • J'ai une base de données K avec 3 serveurs liés L1, L2, L3 à 3 bases de données x, y, z.
  • Dans X, Y, Z J'ai, respectivement, 3 vues appelées v1, v2, v3.
  • Je veux interroger l'Union de V1, V2, V3 par base de données K avec serveur lié L1, L2, L3.

Après quelques tests, c'est la situation:

  1. Dans SSMS, si j'exécute cette pseudo requête SELECT * FROM (L1.V1 u L2.V2 u L3.V3) WHERE some filters La performance est vraiment géniale
  2. Si je crée une vue VK dans la base de données K, qui contient l'union des trois vues, puis je gère la requête SELECT * FROM VK WHERE some filters La performance est pire que le cas 1

Des questions

  • Pourquoi la performance est-elle si différente?
  • Comment puis-je améliorer les performances dans le cas 2?

Je suis intéressé à améliorer les performances dans l'affaire 2 parce que j'ai besoin d'une vue pour cartographier NHBINERNATE dans notre logiciel ...

Merci d'avance, Cordialement

Mise à jour après la publication de John Alan

Ok, j'essaie mais sans résultat. Je ne suis pas un DBA et mes compétences sur la configuration de DB sont vraiment limitées. Pouvons-nous procéder étape par étape?

  1. Sur le serveur distant (called Y) J'ai créé un nouveau compte (called linkedserver) Par Security-> Logins-> Nouveau Connexion. Je sélectionne le nom de connexion puis l'authentification SQL et je choisis un mot de passe. Pour la base de données de Safault, je sélectionne master. Dans server roles onglet I Sélectionnez public. dans User mapping onglet I Sélectionnez les bases de données impliquées dans les requêtes distantes et, pour chacune d'elles, je sélectionne db_ddladmin et public rôle. Ensuite, pour chaque base de données impliquée dans la requête distante, j'ai vérifié l'autorisation effective de l'utilisateur LinkedServer et il y a beaucoup de ALTER et beaucoup de CREATE autorisations mais pas de plan (puis j'ai sélectionné ceci un aussi).

  2. Sur le serveur de base de données (called X) Lorsque le serveur lié à y existe, j'ai créé un serveur lié (called L1). Dans l'onglet Sécurité, j'ai sélectionné local user sa et remote user linkedserver avec son mot de passe.

Quand j'exécute la requête à travers L1 sans vue, j'ai un bon résultat, si je mettez la requête dans une vue à faible performance, rien n'a changé ...

Je pense que j'ai fait du tort, mais je ne sais pas où ...

Pour une meilleure clarté

Ceci est la requête que je fonctionne sans afficher à l'aide de serveur lié:

select * from
(
    select * from dolph.agendasdn.dbo.vistaaccettazionegrp
    union
    select * from dolph.acampanet.dbo.vistaaccettazionegrp
    union
    select * from municipio.dbnet.dbo.vistaaccettazionegrp
) a 
where cognome = 'test' and nome = 'test'

dans la vue je ne mets que ce code

    select * from dolph.agendasdn.dbo.vistaaccettazionegrp
    union
    select * from dolph.acampanet.dbo.vistaaccettazionegrp
    union
    select * from municipio.dbnet.dbo.vistaaccettazionegrp

puis j'ai appelé select * from VIEW where cognome = 'test' and nome = 'test'

Alors..

  • 1ère cas 0-1 secondes.
  • 2ème cas> 15 secondes ...

Je pense que c'est absurde!

plan d'exécution

Le plan d'exécution avec une requête simple, sans l'utilisation d'une vue: enter image description here

le plan d'exécution utilisant la vue: execution plan with view

7
ced

Votre problème commence et se termine par des statistiques et des estimations. J'ai reproduit votre situation sur mes serveurs et j'ai trouvé des astuces intéressantes et une solution de contournement.

Tout d'abord, jetons un coup d'œil à votre plan d'exécution:
[.____] Lorsqu'une vue est utilisée, nous pouvons voir qu'un filtre est appliqué après the requête à distance est exécuté, sans que l'on puisse afficher, aucun filtre n'a été appliqué du tout. La vérité est que le filtre a été appliqué Inside The Query distant, sur le serveur distant, avant de récupérer les données sur le réseau.
[.____] Bien, appliquez évidemment le filtre sur le serveur distant et récupérer ainsi moins de données est une meilleure option, et évidemment, cela ne se produit que lorsqu'il n'utilise pas une vue.

Alors ... qu'est-ce que c'est tellement interstable ...?

Surprenant, quand j'ai changé le filtre de cognome = 'test' à cognome = N'test' (représentation Unicode de la chaîne) La vue a utilisé le même plan d'exécution que la première requête a fait.
[ Pour convertir implicite NVARCHAR à VARCHAR, les statistiques ne pouvaient plus être utilisées et la décision de filtrer localement n'a pas été prise.
[.____] J'ai cherché les statistiques localement, mais la vue n'avait aucune statistique, alors je suppose que la vue utilise les statistiques distantes de manière à ce que la requête ad-hoc ne soit pas, et que prend la mauvaise décision.

OK, alors qu'est-ce qui résout le problème?

J'ai précisé plus tôt qu'il y a une solution de contournement (au moins jusqu'à ce que quelqu'un vienne une meilleure solution), et non, je ne veux pas utiliser unicode pour vos cordes.
[.____] Je voulais d'abord donner une réponse, je dois toujours trouver pourquoi, mais lors de l'utilisation d'une Inline Function SQL Server se comporte exactement la même chose qu'avec la requête (sans vue), le remplacement de la vue avec la fonction donnera le même résultat, dans une simple requête, et avec une bonne peformance (au moins dans mon environnement).

Ma suggestion de code pour vous est:

CREATE FUNCTION fn_anagrafiche2()
RETURNS table
AS
RETURN 
(
    SELECT * 
    FROM dolph2.agendasdn.dbo.vistaanagraficagrp
    UNION
    SELECT * 
    FROM dolph2.acampanet.dbo.vistaanagraficagrp
    UNION
    SELECT * 
    FROM municipio2.dbnet.dbo.vistaanagraficagrp
)
GO

La requête sera alors:

SELECT * 
FROM fn_anagrafiche2()
WHERE cognome = 'prova'

Cela fonctionne sur mes serveurs, mais bien sûr le tester en premier.
[.____] NOTE: Je ne recommande pas d'utiliser SELECT * du tout, car il est sujet aux erreurs futures, je l'ai simplement utilisée parce que c'était dans votre question et qu'il n'était pas nécessaire de changer cela quand je peux ajouter cette remarque à la place :)

5
Roi Gavish