web-dev-qa-db-fra.com

Pourquoi l'exécution d'une requête sur SQL Azure est-elle beaucoup plus lente?

J'ai créé un compte d'essai sur Azure , et j'ai déployé ma base de données à partir de SmarterAsp.

Lorsque j'exécute une requête pivot sur SmarterAsp\MyDatabase, les résultats sont apparus en 2 secondes .

Cependant, l'exécution de la même requête sur Azure\MyDatabase a pris 94 secondes .

J'utilise SQL Server 2014 Management Studio (version d'essai) pour me connecter aux serveurs et exécuter la requête.

Est-ce une différence de vitesse car mon compte est un compte d'essai?

Quelques informations liées à ma question

la requête est:

ALTER procedure [dbo].[Pivot_Per_Day]
@iyear int,
@imonth int,
@iddepartment int

as

declare @columnName Nvarchar(max) = ''
declare @sql Nvarchar(max) =''

select @columnName += quotename(iDay) + ','
from (
        Select day(idate) as iDay
        from kpivalues where year(idate)=@iyear and month(idate)=@imonth
        group by idate
        )x

set @columnName=left(@columnName,len(@columnName)-1)

set @sql ='


Select * from (
select kpiname, target, ivalues, convert(decimal(18,2),day(idate)) as iDay   

from kpi

inner join kpivalues on kpivalues.idkpi=kpi.idkpi

inner join kpitarget on kpitarget.idkpi=kpi.idkpi

inner join departmentbscs on departmentbscs.idkpi=kpi.idkpi

where iddepartment='+convert(nvarchar(max),@iddepartment)+'

group by kpiname,target, ivalues,idate)x

pivot
(
     avg(ivalues)
    for iDay in (' + @columnName + ')
) p'

execute sp_executesql @sql

L'exécution de cette requête sur 3 serveurs différents m'a donné des résultats différents en termes de temps écoulé jusqu'à ce que mon tableau croisé dynamique apparaisse à l'écran:

Azure - Temps écoulé = 100,165 s

Smarterasp.net - Temps écoulé = 2,449 sec

LocalServer - Temps écoulé = 1,716 s

En ce qui concerne mon compte d'essai sur Azure, je l'ai fait avec l'objectif principal de vérifier si j'aurai une meilleure vitesse que Smarter lors de l'exécution d'une procédure stockée comme celle ci-dessus. Je choisis pour ma base de données Niveau de service - Basique, Niveau de performance - Basique (5DTU) et Max. Taille 2 Go.

Ma base de données a 16 tables, 1 table a 145284 lignes et la taille de la base de données est de 11 Mo. C'est une base de données de test pour mon application.

Mes questions sont:

  1. Que puis-je faire pour optimiser cette requête (sp)?
  2. Azure est-il recommandé pour les petites bases de données (100 Mo-1 Go)? Je veux dire performance vs coût!

Conclusions basées sur vos entrées:

  • J'ai apporté des modifications suggérées à la requête et les performances ont été améliorées de plus de 50% - Merci Remus
  • J'ai testé ma requête sur Azure S2 et le temps écoulé pour la requête mise à jour était de 11 secondes.
  • J'ai testé à nouveau ma requête sur P1 et le temps écoulé était de 0,5 seconde :)

  • la même requête mise à jour sur SmarterASP avait un temps écoulé de 0,8 seconde.

Maintenant, c'est clair pour moi quels sont les niveaux dans Azure et à quel point il est important d'avoir une très bonne requête (j'ai même compris ce qu'est un index et son avantage/inconvénient)

Merci à tous, Lucian

23
Lucian Bumb

C'est avant tout une question de performance. Vous avez affaire à un code peu performant de votre part et vous devez identifier le goulot d'étranglement et y remédier. Je parle des mauvaises performances 2 secondes maintenant. Suivez les instructions de Comment analyser les performances de SQL Server . Une fois que vous obtenez cette requête à exécuter localement acceptable pour une application web (moins de 5 ms), vous pouvez poser la question de la porter sur Azure SQL DB. À l'heure actuelle, votre compte d'essai ne fait que mettre en évidence les inefficacités existantes.

Après la mise à jour

...
@iddepartment int
...
iddepartment='+convert(nvarchar(max),@iddepartment)+'
...

alors c'est quoi? la colonne iddepartment est-elle un int ou un nvarchar? Et pourquoi utiliser (max)?

Voici ce que vous devriez faire:

  • paramétrer @iddepartment dans le SQL dynamique interne
  • arrêtez de faire la conversion nvarchar(max). Faites correspondre les types iddepartment et @iddertment
  • assurer les index sur iddepartment et tous les idkpis

Voici comment paramétrer le SQL interne:

set @sql =N'
Select * from (
select kpiname, target, ivalues, convert(decimal(18,2),day(idate)) as iDay   
from kpi
inner join kpivalues on kpivalues.idkpi=kpi.idkpi
inner join kpitarget on kpitarget.idkpi=kpi.idkpi
inner join departmentbscs on departmentbscs.idkpi=kpi.idkpi
where iddepartment=@iddepartment
group by kpiname,target, ivalues,idate)x
pivot
(
     avg(ivalues)
    for iDay in (' +@columnName + N')
) p'

execute sp_executesql @sql, N'@iddepartment INT', @iddepartment;

Les indices de couverture sont, de loin, la solution la plus importante. Cela nécessite évidemment plus d'informations qu'ici. Lire Conception d'index y compris tous les sous-chapitres.

Comme un commentaire plus général: ce genre de requêtes convient columnstores plus que rowstore, bien que je pense que la taille des données est, fondamentalement, minuscule. Azure SQL DB prend en charge les index de colonnes columnstore pouvant être mis à jour, vous pouvez l'expérimenter en prévision d'une taille de données sérieuse. Ils nécessitent Enterprise/Development sur la boîte locale, c'est vrai.

13
Remus Rusanu

(pdate: la question d'origine a été modifiée pour demander également comment optimiser la requête - ce qui est également une bonne question. La question d'origine était pourquoi la différence qui est le sujet de cette réponse).

Les performances des requêtes individuelles sont fortement affectées par les niveaux de performances. Je sais que la documentation implique que les niveaux concernent la charge, ce qui n'est pas strictement vrai.

Je voudrais relancer votre test avec une base de données S2 comme point de départ et partir de là.

Être abonné à un essai n'affecte pas en soi les performances, mais avec le compte gratuit, vous utilisez probablement un niveau B qui n'est pas vraiment utilisable par quelque chose de réel - certainement pas pour une requête qui prend 2 secondes pour s'exécuter localement.

Même le déplacement entre, disons, S1 et S2 montrera une différence notable dans les performances d'une requête individuelle. Si vous voulez expérimenter, n'oubliez pas que vous êtes facturé un jour pour "n'importe quelle partie d'une journée", ce qui est probablement correct pour le niveau S, mais soyez prudent lorsque vous testez le niveau P.

Pour le fond; lorsque Azure a introduit les nouveaux niveaux l'année dernière, ils ont changé le modèle d'hébergement pour SQL. Auparavant, de nombreuses bases de données s'exécutaient sur un sqlserver.exe partagé. Dans le nouveau modèle, chaque base de données obtient effectivement son propre sqlserver.exe qui s'exécute dans un sandbox à ressources limitées. C'est ainsi qu'ils contrôlent "l'utilisation des DTU" mais affectent également les performances générales.

13
Frans

Cela n'a rien à voir avec le fait que votre compte est en essai, c'est en raison du niveau de performance inférieur que vous avez sélectionné.

Dans d'autres services (SmarterAsp) et exécutant une instance locale, vous n'avez probablement pas de restrictions de performances plutôt que de taille.

À ce stade, il est impossible de définir ce que signifie réellement DTU/quel type de numéro de DTU est associé à un serveur SQL installé sur votre machine locale ou dans tout autre fournisseur d'hébergement.

Cependant, il existe de bonnes analyses ( https://cbailiss.wordpress.com/2014/09/16/performance-in-new-Azure-sql-database-performance-tiers/ ) effectuées concernant ceci mais rien d'officiel.

2
Low Flying Pelican