Fonction évaluée par table – L'ordre par est ignoré dans la sortie

Nous passons de SQL Server 2008 à SQL Server 2012 et remarquons immédiatement que toutes nos fonctions de table ne fournissent plus leur contenu de table temporaire dans l'ordre correct.

CODE:

INSERT INTO @Customer SELECT Customer_ID, Name, CASE WHEN Expiry_Date < GETDATE() then 1 WHEN Expired = 1 then 1 ELSE 0 END from Customer **order by Name** 

Dans SQL Server 2008, cette fonction renvoie les clients sortingés par nom. Dans SQL Server 2012, il renvoie la table non sortingée. La "command par" est ignorée dans SQL 2012.

Devons-nous réécrire toutes les fonctions pour inclure un sort_id puis les sortinger quand ils sont appelés dans l'application principale ou y a-t-il une solution facile?

Il y avait deux choses qui ne marchaient pas avec votre approche originale.

  1. Lors de l'insertion dans la table, il n'a jamais été garanti que ORDER BY sur l' INSERT ... SELECT ... ORDER BY serait l'ordre dans lequel les lignes étaient réellement insérées.
  2. Lors de la sélection SQL Server ne garantit pas que SELECT sans un ORDER BY returnnera les lignes dans un ordre particulier tel que l'ordre d'insertion de toute façon.

En 2012, il semble que le comportement a changé par rapport à l'élément 1. Il ignore maintenant généralement ORDER BY sur l' SELECT qui est la source d'un INSERT

 DECLARE @T TABLE(number int) INSERT INTO @T SELECT number FROM master..spt_values ORDER BY name 

Plan 2008

Plan 2008

Plan 2012

Plan 2012

La raison du changement de comportement est que dans les versions précédentes, SQL Server produisait un plan partagé entre les exécutions avec SET ROWCOUNT 0 (désactivé) et SET ROWCOUNT N L'opérateur de sorting était uniquement là pour garantir la sémantique correcte dans le cas où le plan était exécuté par une session avec un set ROWCOUNT non nul. L'opérateur TOP à gauche de celui-ci est un ROWCOUNT TOP .

SQL Server 2012 produit maintenant des plans distincts pour les deux cas, il n'est donc pas nécessaire de les append à la version ROWCOUNT 0 du plan.

Un sorting peut encore apparaître dans le plan en 2012 si le SELECT a un TOP explicite défini (autre que TOP 100 PERCENT ) mais cela ne garantit toujours pas l'ordre d'insertion réel des lignes, le plan pourrait alors avoir un autre sorting après que le TOP N est établi pour get les lignes dans l'ordre de l'index clusterisé par exemple.

Pour l'exemple de votre question, je voudrais simplement ajuster le code appelant pour spécifier le ORDER BY name si c'est ce dont il a besoin.

En ce qui concerne votre idée sort_id des garanties de command dans SQL Server, il est garanti lors de l'insertion dans une table avec IDENTITY que la command qui leur est allouée sera sort_id à la command ORDER BY , vous pouvez également faire

 DECLARE @Customer TABLE ( Sort_Id INT IDENTITY PRIMARY KEY, Customer_ID INT, Name INT, Expired BIT ) INSERT INTO @Customer SELECT Customer_ID, Name, CASE WHEN Expiry_Date < Getdate() THEN 1 WHEN Expired = 1 THEN 1 ELSE 0 END FROM Customer ORDER BY Name 

mais vous devrez toujours order par sort_id dans vos requêtes de sélection car il n'y a pas de command garantie sans cela (peut-être que cette approche sort_id pourrait être utile dans le cas où les colonnes d'origine utilisées pour la command ne sont pas copiées dans la variable table)

append une colonne nommée rowno à la table @Customer

 INSERT INTO @Customer SELECT ROW_NUMBER()over(order by Name)rowno,Customer_ID, Name, CASE WHEN Expiry_Date < GETDATE() then 1 WHEN Expired = 1 then 1 ELSE 0 END from Customer