7
votes

Appels multiples Row_Number () dans une seule requête SQL

J'essaie de configurer certaines données pour calculer plusieurs méditas dans SQL Server 2008, mais j'ai un problème de performance. En ce moment, j'utilise ce modèle ([un autre exemple bas ). Oui, je n'utilise pas de CTE, mais en utilisant un problème ne résout pas le problème que je vais de toute façon et que la performance est médiocre, car les sous-requêtes Row_Number exécutées en série, non parallèles.

Voici un exemple complet. Au-dessous de la SQL, j'explique le problème plus. xxx

Le problème avec cette requête est que SQL Server exécute les deux "Row__Number () sur ..." Sous-requêtes dans série, pas en parallèle. Donc, si je dispose 10 de ces calculs de nnatation, il les calculera les un après l'autre et que je reçois une croissance linéaire, qui pue. J'ai un système de 32 Go à 8 voies que j'exécute cette requête et j'aimerais du parallélisme. J'essaie d'exécuter ce type de requête sur une table de 5 000 000 rangées.

Je peux le dire à son faire en examinant le plan de requête et en voyant les sortes dans le même chemin d'exécution (affichant que le XML du plan de requête ne fonctionnerait pas vraiment bien.

Donc, ma question est la suivante: comment puis-je modifier cette requête afin que les requêtes de row_number soient exécutées en parallèle? Y a-t-il une technique complètement différente que je puisse utiliser pour préparer les données pour plusieurs calculs médians?


5 commentaires

+1, assez de code pour l'essayer sur mon système !!


+1, parce que je ne savais pas que vous pouviez utiliser des clauses en dehors des fonctions de classement - dans SQL 2005 également, pas moins. Woot!


Philip: Pour les fonctions d'agrégat normales, seule la partition par clause cependant, pas la commande par partie :-(


@RBARRY: AVG, Somme, Compte, Max, Min et similaires Devraient donner le même résultat, peu importe l'ordre de l'entrée.


Remus: La commande par partie est ce qui implique l'agrégation séquentielle. En d'autres termes, la somme (..) sur (commander par ID) produirait des totaux de fonctionnement (selon la norme SQL). Malheureusement, SQL Server ne l'applique pas.


3 Réponses :


3
votes

Chaque rangée oblige les lignes à trier d'abord. Étant donné que vos deux RN ont une commande différente par des conditions, la requête doit produire le résultat, puis le commander pour la première fois (il peut être commandé déjà par), produisez le RN, puis commandez-le pour la seconde RN et produit le deuxième résultat RN. Il n'ya tout simplement pas de poussière de pixie magique qui peut matérialiser une valeur de numéro de ligne sans compter où la ligne est dans l'ordre requis.


3 commentaires

Je comprends qu'il n'y a pas de poussière de pixie magique disponible, il y a une pénurie mondiale. :) Je sais que cela ne pouvait pas comprendre ce que le RN est sans premier ordre. Comment puis-je le configurer de sorte qu'il commande de différentes manières en parallèle à calcaire le rn? Existe-t-il une technique pour la casser dans plusieurs requêtes, puis rejoindre les ensembles de résultats? Je ne suis pas marié à utiliser le style RN, donc toute idée constructive serait appréciée. Je ne peux pas être la première personne du monde qui souhaite prendre un ensemble de données et calculer plusieurs médiums à la fois efficace! Pour ce faire, les données doivent être triées de différentes manières.


Est vraiment difficile avec Row_numbers sur 8 commandes différentes et avec une partition selon les exigences. Même avec des sous-coutumes que peut être paralélisé est peu probable qu'ils le feront. Les options de paralèle sont disponibles une option pour partitionner l'exécution d'une seule opération, comme une numérisation de table, non pour diviser plusieurs sous-requêtes différentes. Je reviendrais les exigences et reconsidérerais le besoin de tous les rangées ...


Malheureusement, calculer une médiane exige que les données soient triées dans l'ordre. Le rang_number vous dit simplement simplement comment ces données ont été triées pour un champ donné. Thx pour l'aide jusqu'à présent ...



2
votes

Je ne suis pas sûr que cela puisse parlementer cela, car il doit faire des analyses non transférées (Population WRT VS Miles carrés). Ils entreront en conflit avec chacun sur disque, il doit donc tout faire en mémoire au moins une fois, tout d'abord, il pourrait être admissible à la parallélisation, si c'est assez grand.

Dans tout événement, les suivants se produisent de manière significative (40% ) Plus rapide pour moi: P>

INSERT INTO TestMedian 
SELECT abs(id)%3,abs(id)%2,abs(id)%5, abs(id), colid * 10000
  From master.sys.syscolumns, (select top 10 * from master.dbo.spt_values)a


1 commentaires

Merci. Je teste cette approche sur mes données réelles définies maintenant pour voir si les comptes de ligne sont paralléliques. Sur un petit sous-ensemble, il semblait prometteur.



1
votes

Une pensée latérale: si vous avez besoin de ces données souvent et / ou rapidement, et que le jeu de données sous-jacent ne change pas fréquemment (pour des valeurs raisonnablement élevées de "fréquemment"), pourriez-vous précalculer l'une de ces valeurs et les stocker dans une forme de table pré-agrégée?

(Oui, c'est la démonormalisation, mais si vous avez besoin de performance sur tout le reste, cela vaut la peine d'être envisagé.)


2 commentaires

Je voulais dire "dénormalisation" là-bas. Honnête.


Je te crois :). Malheureusement, je ne vois pas une étape de pré-agrégation ici, cependant. Dans cet exemple, les tailles de population sont réparties sur un ensemble de dimensions. Pour chaque ensemble de dimensions, je dois trouver la valeur médiane de la taille de la population. La seule pré-agrégation à laquelle je peux penser est de remplacer les dimensions individuelles avec un identifiant de manière à ce que le partitionnement, le regroupement et la jonction est effectué sur moins de colonnes (pourrait en vaut vraiment la peine).