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 =).
Après quelques tests, c'est la situation:
SELECT * FROM (L1.V1 u L2.V2 u L3.V3) WHERE some filters
La performance est vraiment génialeSELECT * FROM VK WHERE some filters
La performance est pire que le cas 1Je 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?
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).
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ù ...
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..
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:
le plan d'exécution utilisant la vue:
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 :)