T-SQL - Was ist der effizienteste Weg, um eine Tabelle zu durchlaufen, bis eine Bedingung erfüllt ist

10

Ich habe eine Programmieraufgabe im Bereich T-SQL.

Aufgabe:

  1. Die Leute wollen in einen Aufzug, jede Person hat ein bestimmtes Gewicht.
  2. Die Reihenfolge der in der Schlange wartenden Personen wird durch die Spaltenumdrehung bestimmt.
  3. Der Aufzug hat eine maximale Kapazität von <= 1000 lbs.
  4. Geben Sie den Namen der letzten Person zurück, die den Aufzug betreten kann, bevor er zu schwer wird!
  5. Der Rückgabetyp sollte table sein

Geben Sie hier die Bildbeschreibung ein

Frage: Was ist der effizienteste Weg, um dieses Problem zu lösen? Wenn die Schleife korrekt ist, gibt es Raum für Verbesserungen?

Ich habe eine Schleife und # temporäre Tabellen verwendet, hier meine Lösung:

set rowcount 0
-- THE SOURCE TABLE "LINE" HAS THE SAME SCHEMA AS #RESULT AND #TEMP
use Northwind
go

declare @sum int
declare @curr int
set @sum = 0
declare @id int

IF OBJECT_ID('tempdb..#temp','u') IS NOT NULL
    DROP TABLE #temp

IF OBJECT_ID('tempdb..#result','u') IS NOT NULL
    DROP TABLE #result

create table #result( 
    id int not null,
    [name] varchar(255) not null,
    weight int not null,
    turn int not null
)

create table #temp( 
    id int not null,
    [name] varchar(255) not null,
    weight int not null,
    turn int not null
)

INSERT into #temp SELECT * FROM line order by turn

 WHILE EXISTS (SELECT 1 FROM #temp)
  BEGIN
   -- Get the top record
   SELECT TOP 1 @curr =  r.weight  FROM  #temp r order by turn  
   SELECT TOP 1 @id =  r.id  FROM  #temp r order by turn

    --print @curr
    print @sum

    IF(@sum + @curr <= 1000)
    BEGIN
    print 'entering........ again'
    --print @curr
      set @sum = @sum + @curr
      --print @sum
      INSERT INTO #result SELECT * FROM  #temp where [id] = @id  --id, [name], turn
      DELETE FROM #temp WHERE id = @id
    END
     ELSE
    BEGIN    
    print 'breaaaking.-----'
      BREAK
    END 
  END

   SELECT TOP 1 [name] FROM #result r order by r.turn desc 

Hier das Create-Skript für die Tabelle, die ich mit Northwind zum Testen verwendet habe:

USE [Northwind]
GO

/****** Object:  Table [dbo].[line]    Script Date: 28.05.2018 21:56:18 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[line](
    [id] [int] NOT NULL,
    [name] [varchar](255) NOT NULL,
    [weight] [int] NOT NULL,
    [turn] [int] NOT NULL,
PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
UNIQUE NONCLUSTERED 
(
    [turn] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[line]  WITH CHECK ADD CHECK  (([weight]>(0)))
GO

INSERT INTO [dbo].[line]
    ([id], [name], [weight], [turn])
VALUES
    (5, 'gary', 800, 1),
    (3, 'jo', 350, 2),
    (6, 'thomas', 400, 3),
    (2, 'will', 200, 4),
    (4, 'mark', 175, 5),
    (1, 'james', 100, 6)
;
Legenden
quelle

Antworten:

16

Sie sollten versuchen, Schleifen generell zu vermeiden. Sie sind normalerweise weniger effizient als satzbasierte Lösungen und weniger lesbar.

Das Folgende sollte ziemlich effizient sein.

Dies gilt umso mehr, wenn die Spalten name und weight INCLUDE-im Index enthalten sein könnten , um die Schlüsselsuche zu vermeiden.

Es kann den eindeutigen Index in der Reihenfolge scannen turnund die laufende Summe der WeightSpalte berechnen - und dann verwendenLEAD dieselben Ordnungskriterien, um zu sehen, wie hoch die laufende Summe in der nächsten Zeile sein wird.

Sobald die erste Zeile gefunden wird, in der diese 1000 überschreitet oder ist NULL(was anzeigt, dass keine nächste Zeile vorhanden ist), kann der Scan gestoppt werden.

WITH T1
     AS (SELECT *,
                SUM(Weight) OVER (ORDER BY turn ROWS UNBOUNDED PRECEDING) AS cume_weight
         FROM   [dbo].[line]),
     T2
     AS (SELECT LEAD(cume_weight) OVER (ORDER BY turn) AS next_cume_weight,
                *
         FROM   T1)
SELECT TOP 1 name
FROM   T2
WHERE  next_cume_weight > 1000
        OR next_cume_weight IS NULL
ORDER  BY turn 

Ausführungsplan

Geben Sie hier die Bildbeschreibung ein

In der Praxis scheint es ein paar Zeilen vor dem unbedingt erforderlichen zu lesen - es sieht so aus, als würde jedes Fenster-Spool / Stream-Aggregat-Paar zwei zusätzliche Zeilen lesen.

Für die Beispieldaten in der Frage müssten im Idealfall nur zwei Zeilen aus dem Index-Scan gelesen werden, in Wirklichkeit jedoch 6, aber dies ist kein signifikantes Effizienzproblem und verschlechtert sich nicht, wenn der Tabelle weitere Zeilen hinzugefügt werden (wie in) diese Demo )

Für diejenigen, die an dieser Ausgabe interessiert sind, query_trace_column_valueswird unten ein Bild mit den von jedem Operator ausgegebenen Zeilen (wie durch das erweiterte Ereignis gezeigt) angezeigt. Die Zeilen werden in der angegebenen row_idReihenfolge ausgegeben (beginnend mit 47der ersten Zeile, die vom Index-Scan gelesen wurde, und endend mit 113für TOP).

Klicken Sie auf das Bild unten, um es zu vergrößern, oder sehen Sie sich alternativ die animierte Version an, um den Ablauf zu vereinfachen .

Anhalten der Animation an dem Punkt, an dem das rechte Stream-Aggregat seine erste Zeile ausgegeben hat (für gary - turn = 1). Es scheint offensichtlich, dass es darauf gewartet hat, seine erste Zeile mit einem anderen WindowCount zu erhalten (für Jo - turn = 2). Und die Fensterspule gibt die erste "Jo" -Zeile erst frei, wenn sie die nächste Zeile mit einer anderen gelesen hatturn -Zeile (für thomas - turn = 3).

Die Fensterspule und das Stream-Aggregat bewirken also, dass eine zusätzliche Zeile gelesen wird, und es gibt vier davon im Plan - daher 4 zusätzliche Zeilen.

Geben Sie hier die Bildbeschreibung ein

Es folgt eine Erläuterung der oben gezeigten Spalten (basierend auf Informationen hier ).

  • Knotenname: Index-Scan, Knoten-ID: 15, Spaltenname: ID-Basistabellenspalte, die vom Index abgedeckt wird
  • NodeName: Index-Scan, NodeId: 15, ColumnName: Dreht die vom Index abgedeckte Basistabellenspalte
  • NodeName: Clustered Index Seek, NodeId: 17, ColumnName: Spalte der Gewichtsbasis- Tabelle, die aus der Suche abgerufen wurde
  • NodeName: Clustered Index Seek, NodeId: 17, ColumnName: Spalte der Namensbasis- Tabelle, die aus der Suche abgerufen wurde
  • NodeName: Segment, NodeId: 13, ColumnName: Segment1010 Gibt 1 am Anfang einer neuen Gruppe zurück oder andernfalls null. Als Nein Partition Byin der SUMeinzigen bekommt die erste Reihe 1
  • NodeName: Sequence Project, NodeId: 12, ColumnName: RowNumber1009 row_number() innerhalb der durch das Segment1010-Flag angegebenen Gruppe. Da sich alle Zeilen in derselben Gruppe befinden, werden ganze Zahlen von 1 bis 6 aufgestiegen. Wird in Fällen wie z rows between 5 preceding and 2 following. B. zum Filtern von Zeilen mit rechten Rahmen verwendet . (oder wie für LEADspäter)
  • NodeName: Segment, NodeId: 11, ColumnName: Segment1011 Gibt 1 am Anfang einer neuen Gruppe zurück oder andernfalls null. Als Nein Partition Byin der SUMeinzigen erhält die erste Zeile 1 (wie Segment1010)
  • NodeName: Window Spool, NodeId: 10, ColumnName: WindowCount1012 Attribut, das Zeilen gruppiert , die zu einem Fensterrahmen gehören. Diese Fensterspule verwendet den Fall "Fast Track" für UNBOUNDED PRECEDING. Wo es zwei Zeilen pro Quellzeile ausgibt. Eins mit den kumulativen Werten und eins mit den Detailwerten. Obwohl es keinen sichtbaren Unterschied in den Zeilen gibt, die von query_trace_column_valuesangezeigt werden, gehe ich davon aus, dass kumulative Spalten in der Realität vorhanden sind.
  • NodeName: Stream Aggregate, NodeId: 9, ColumnName: Expr1004, Count(*) gruppiert nach WindowCount1012 gemäß Plan, aber tatsächlich eine laufende Anzahl
  • NodeName: Stream Aggregate, NodeId: 9, ColumnName: Expr1005, SUM(weight) gruppiert nach WindowCount1012 gemäß Plan, aber tatsächlich der laufenden Gewichtssumme (dh cume_weight)
  • NodeName: Segment, NodeId: 7, ColumnName: Expr1002 CASE WHEN [Expr1004]=(0) THEN NULL ELSE [Expr1005] END - Sehen Sie nicht, wie COUNT(*)0 sein kann, also wird immer sum ( cume_weight) ausgeführt.
  • Knotenname: Segment, Knoten-ID: 7, Spaltenname: Segment1013 Nein partition byin der LEADersten Zeile erhält 1. Alle verbleibenden erhalten null
  • NodeName: Sequenzprojekt, NodeId: 6, ColumnName: RowNumber1006 row_number() innerhalb der durch das Segment1013-Flag angegebenen Gruppe. Da sich alle Zeilen in derselben Gruppe befinden, sind dies ganze Zahlen von 1 bis 4
  • NodeName: Segment, NodeId: 4, ColumnName: BottomRowNumber1008 RowNumber1006 + 1, da dies die LEADnächste Zeile erfordert
  • NodeName: Segment, NodeId: 4, ColumnName: TopRowNumber1007 RowNumber1006 + 1, da dies die LEADnächste Zeile erfordert
  • NodeName: Segment, NodeId: 4, ColumnName: Segment1014 Nein partition byin der LEADersten Zeile erhält 1. Alle verbleibenden erhalten null
  • NodeName: Window Spool, NodeId: 3, ColumnName: WindowCount1015 Attribut, das Zeilen, die zu einem Fensterrahmen gehören, unter Verwendung der vorherigen Zeilennummern gruppiert. Der Fensterrahmen für LEADhat maximal 2 Zeilen (die aktuelle und die nächste)
  • NodeName: Stream Aggregate, NodeId: 2, ColumnName: Expr1003 LAST_VALUE([Expr1002]) für dieLEAD(cume_weight)
Martin Smith
quelle
6

Ebenso neugierig (da in der Frage T-SQL steht) ist es auch möglich, dieses Problem mit SQLCLR effizient zu lösen.

Die Idee ist, die Zeilen einzeln zu lesen turn, bis weight1000 überschritten werden (oder uns die Zeilen ausgehen), und dann die letzten zurückzugebenname Lesevorgang zurückzugeben.

Der Quellcode lautet:

using Microsoft.SqlServer.Server;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;

public partial class UserDefinedFunctions
{
    [SqlFunction(DataAccess = DataAccessKind.Read,
        SystemDataAccess = SystemDataAccessKind.None,
        IsDeterministic = true, IsPrecise = true)]
    [return: SqlFacet(IsFixedLength = false, IsNullable = true, MaxSize = 255)]
    public static SqlString Elevator()
    {
        const string query =
            @"SELECT L.[name], L.[weight]
            FROM dbo.line AS L
            ORDER BY L.turn;";

        using (var con = new SqlConnection("context connection = true"))
        {
            con.Open();
            using (var cmd = new SqlCommand(query, con))
            {
                var rdr = cmd.ExecuteReader(CommandBehavior.SingleResult);
                var name = SqlString.Null;
                var total = 0;

                while (rdr.Read() && (total += rdr.GetInt32(1)) <= 1000)
                {
                    name = rdr.GetSqlString(0);
                }
                return name;
            }
        }
    }
}

Die kompilierte Assembly- und T-SQL-Funktion:

CREATE ASSEMBLY Elevator AUTHORIZATION [dbo]
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300606C0E5B0000000000000000E00022200B013000000C000000060000000000004A2A0000002000000040000000000010002000000002000004000000000000000600000000000000008000000002000000000000030060850000100000100000000010000010000000000000100000000000000000000000F82900004F00000000400000A802000000000000000000000000000000000000006000000C000000C02800001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000500A000000200000000C000000020000000000000000000000000000200000602E72737263000000A80200000040000000040000000E0000000000000000000000000000400000402E72656C6F6300000C00000000600000000200000012000000000000000000000000000040000042000000000000000000000000000000002C2A0000000000004800000002000500F0200000D007000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B30030070000000010000117201000070730600000A0A066F0700000A723500007006730800000A0B07176F0900000A0C7E0A00000A0D1613042B0808166F0B00000A0D086F0C00000A2C14110408176F0D00000A5825130420E803000031DC091305DE14072C06076F0E00000ADC062C06066F0E00000ADC11052A011C000002001D003C59000A0000000002000B005863000A000000001E02280F00000A2A42534A4201000100000000000C00000076342E302E33303331390000000005006C000000AC010000237E0000180200002002000023537472696E677300000000380400008801000023555300C0050000100000002347554944000000D00500000002000023426C6F620000000000000002000001471502000900000000FA01330016000001000000110000000200000002000000010000000F000000050000000200000001000000020000000000E70001000000000006008A00A9010600BC00A9010600610096010F00C901000006000202F9000A0075005C010A003E005C010A0038005C010A00AA005C010A00DD00D8010A00120109020A002D0009020A00400109020A00050120010A00770113000A003301200106004D00F900000000000A00000000000100010001001000ED0100001500010001005020000000009600870150000100E820000000008618900106000200000000000000090090010100110090010600190090010A00310090010600490090010600590090011E0071000001060061009001230061004E012A005100F40031006900DA003500810028003B00810001003F0089005900060029009001060020002300860024002B00CE012E000B0055002E0013005E002E001B007D00100044000480000000000000000000000000000000008701000004000000000000000000000047001F000000000004000000000000000000000047001300000000000000000000476574496E743332003C4D6F64756C653E0053797374656D2E44617461006D73636F726C696200526561640053716C436F6D6D616E640053797374656D446174614163636573734B696E640049446973706F7361626C6500446973706F73650044656275676761626C654174747269627574650053716C46756E6374696F6E41747472696275746500436F6D70696C6174696F6E52656C61786174696F6E734174747269627574650053716C46616365744174747269627574650052756E74696D65436F6D7061746962696C6974794174747269627574650047657453716C537472696E6700456C657661746F722E646C6C004E756C6C0053797374656D004F70656E004462436F6E6E656374696F6E0053716C436F6E6E656374696F6E0053797374656D2E446174612E436F6D6D6F6E004462446174615265616465720053716C446174615265616465720045786563757465526561646572004D6963726F736F66742E53716C5365727665722E53657276657200436F6D6D616E644265686176696F7200456C657661746F72002E63746F720053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F6465730053797374656D2E446174612E53716C54797065730055736572446566696E656446756E6374696F6E73004F626A6563740053797374656D2E446174612E53716C436C69656E740000003363006F006E007400650078007400200063006F006E006E0065006300740069006F006E0020003D00200074007200750065000081510D000A00200020002000200020002000200020002000200020002000530045004C004500430054000D000A0020002000200020002000200020002000200020002000200020002000200020004C002E005B006E0061006D0065005D002C000D000A0020002000200020002000200020002000200020002000200020002000200020004C002E005B007700650069006700680074005D000D000A00200020002000200020002000200020002000200020002000460052004F004D002000640062006F002E006C0069006E00650020004100530020004C000D000A002000200020002000200020002000200020002000200020004F0052004400450052002000420059000D000A0020002000200020002000200020002000200020002000200020002000200020004C002E007400750072006E003B000D000A00200020002000200020002000200020002000200020002000006C68AC85076C6945BCECB2CE73B9787F000420010108032000010520010111110D0706122D123112351129081129042001010E062002010E122D0620011235113D0306112905200111290803200002042001080802060E08B77A5C561934E08904000011290801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F7773010801000200000000008146010004005455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A446174614163636573730100000054557F4D6963726F736F66742E53716C5365727665722E5365727665722E53797374656D446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D342E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038391053797374656D446174614163636573730000000054020F497344657465726D696E69737469630154020949735072656369736501310100030054020D497346697865644C656E6774680054020A49734E756C6C61626C65015408074D617853697A65FF00000000000000606C0E5B00000000020000001C010000DC280000DC0A000052534453F8D0A90B6069F74DB5FBFABECC9D213901000000633A5C75736572735C7061756C775C736F757263655C7265706F735C4461746162617365325C4461746162617365325C6F626A5C52656C656173655C456C657661746F722E7064620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000202A000000000000000000003A2A00000020000000000000000000000000000000000000000000002C2A0000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF2500200010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001000000018000080000000000000000000000000000001000100000030000080000000000000000000000000000001000000000048000000584000004C02000000000000000000004C0234000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000000000000000000000000000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B004AC010000010053007400720069006E006700460069006C00650049006E0066006F0000008801000001003000300030003000300034006200300000002C0002000100460069006C0065004400650073006300720069007000740069006F006E000000000020000000300008000100460069006C006500560065007200730069006F006E000000000030002E0030002E0030002E00300000003A000D00010049006E007400650072006E0061006C004E0061006D006500000045006C0065007600610074006F0072002E0064006C006C00000000002800020001004C006500670061006C0043006F00700079007200690067006800740000002000000042000D0001004F0072006900670069006E0061006C00460069006C0065006E0061006D006500000045006C0065007600610074006F0072002E0064006C006C0000000000340008000100500072006F006400750063007400560065007200730069006F006E00000030002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000030002E0030002E0030002E0030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C0000004C3A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
WITH PERMISSION_SET = SAFE;
GO
CREATE FUNCTION dbo.Elevator ()
RETURNS nvarchar(255)
AS EXTERNAL NAME Elevator.UserDefinedFunctions.Elevator;

Das Ergebnis erhalten:

SELECT dbo.Elevator();
Paul White 9
quelle
1

Leichte Abweichung von Martin Smiths Lösung

SELECT top 1 name
FROM (
    SELECT id, name, weight, turn
         , SUM(weight) OVER (ORDER BY turn) AS cumulative_weight
    FROM line                               
) as T
WHERE cumulative_weight <= 1000
ORDER BY turn DESC 

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ist der Standardfensterrahmen, daher habe ich das nicht deklariert.

Anstelle des nächsten kumulativen Gewichts wird ein Prädikat für das aktuelle kumulative Gewicht verwendet.

Ich habe keinen Plan überprüft, daher kann ich nicht sagen, ob diesbezüglich ein Unterschied besteht.

Lennart
quelle
Ich sehe, ich bin umgeben von DB-Freaks :-). Ich muss alle Schlüsselwörter überprüfen, die ihr erwähnt, um zu verstehen, was sie tun. Ich habe nur einen Blick darauf geworfen Client statistics --> Total Execution Time, nicht den, Actual execution plander hier wahrscheinlich am interessantesten ist. Ab Client StatisticsIhre Lösung ist ein klein wenig langsamer als Martin. Danke für die zusätzlichen Infos. Mit welcher Methode können Leistungsunterschiede zwischen verschiedenen Ansätzen gemessen werden?
Legenden
1
Ich befürchte, dass meine Kenntnisse über SQL Server sehr begrenzt sind, so dass ich nicht viel Einblick habe, welche Metriken verwendet werden sollen. Martin hat einen db <> Geigenlink in seiner Antwort, vielleicht können Sie sich die Pläne dort ansehen.
Lennart
1
Ich habe die Pläne auch nicht überprüft, würde mir aber vorstellen, dass dies wahrscheinlich die laufende Summe über die gesamte Tabelle berechnet und dann die resultierenden Zeilen sortiert, die mit dem WO übereinstimmen. Ich bezweifle, dass die Prüfbeschränkung verwendet wird, um zu wissen, dass die laufende Summe streng aufsteigend ist und vorzeitig aufhören kann. Auch in SQL Server, außer wenn das Fensteraggregat im Batch-Modus verwendet wird, ist die Angabe von ROWS anstelle von RANGE vorzuziehen, selbst wenn keine Duplikate vorhanden sind, da sich die Fensterspool im Speicher befindet, nicht auf der Festplatte
Martin Smith,
@ MartinSmith, interessant. In Ihrer Lösung ermöglicht LEAD es, das Prädikat next_cume_weight <10000 in T1 zu verschieben und frühzeitig aus dem Index-Scan auszusteigen. Ich habe den Plan für meine Abfrage überprüft und ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWeinen Sequence Project (Compute Scalar)Operator eingeführt. Unnötig zu sagen, ich habe keine Ahnung, was das bedeutet :-)
Lennart
1
Der Index liefert die Zeilen in der Reihenfolge, die für Summe, Lead und Top benötigt wird. Sobald top seine erste Zeile erhält, kann es aufhören, weitere Zeilen anzufordern, und die Ausführung kann gestoppt werden.
Martin Smith
0

Sie können einen Join gegen sich selbst durchführen:

select 
    a.id, a.turn, a.game, 
    coalesce(sum(b.weight), 0) as cumulative_weight
from
    table a
left join 
    table b
on
    a.turn > b.turn
group by
    a.id, a.turn, a.game ;

Diese Art von Dingen ist nicht sehr effizient, da sie eine Auswahl pro Zeile verursachen. Aber zumindest wird es als eine einzige Aussage ausgedrückt.

Wenn Sie dies nicht vollständig in SQL tun müssen, können Sie einfach alle Zeilen auswählen und sie durchlaufen.

Sie können dasselbe auch in einer gespeicherten Prozedur ohne die temporäre Tabelle tun. Halten Sie einfach die Summe und den Namen der letzten Zeile in einer Variablen.

ypercubeᵀᴹ
quelle
Entschuldigung, ich weiß nicht, wie ich es mit einem machen self-joinsoll. Wenn Sie ein kleines reproduzierbares Beispiel machen könnten, habe ich meiner Frage die Tabellendefinition hinzugefügt. Mein SQL ist schlecht ... Ich brauche den Namen der Person, die <= 1000 lbs am nächsten ist.
Legenden
Es sieht so aus, als ob Ihr Update in Ordnung ist. Sie müssen ein wenig damit herumspielen, wenn Sie möchten, dass es genau die Ausgabe liefert. Aber wie ich schon sagte, es ist nicht sehr effizient
In Ordnung? Ich bekomme null für Person mit ID 5 ...
Legends
das ist seltsam, ich würde erwarten, dass sum () 0 für eine Summe über 0 Zeilen
SUMME über 0 Zeilen ist (leider) nicht 0. Sie müssen COALESCE()oder ISNULL()Funktion oder einen CASEAusdruck verwenden, um es 0 zu machen.
ypercubeᵀᴹ