T-SQL - Cách hiệu quả nhất để lặp qua bảng cho đến khi điều kiện được đáp ứng


10

Trong có một nhiệm vụ lập trình trong lĩnh vực T-SQL.

Bài tập:

  1. Mọi người muốn vào trong thang máy mỗi người có một trọng lượng nhất định.
  2. Thứ tự của những người chờ xếp hàng được xác định bởi lượt cột.
  3. Thang máy có công suất tối đa <= 1000 lbs.
  4. Trả lại tên của người cuối cùng có thể vào thang máy trước khi nó quá nặng!
  5. Kiểu trả về phải là bảng

nhập mô tả hình ảnh ở đây

Câu hỏi: Cách hiệu quả nhất để giải quyết vấn đề này là gì? Nếu lặp là đúng thì có chỗ nào để cải thiện không?

Tôi đã sử dụng một vòng lặp và # bảng tạm thời, đây là giải pháp của tôi:

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 

Ở đây, kịch bản Tạo cho bảng tôi đã sử dụng Northwind để thử nghiệm:

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)
;

Câu trả lời:


16

Bạn nên cố gắng tránh các vòng lặp nói chung. Chúng thường kém hiệu quả hơn các giải pháp dựa trên thiết lập cũng như ít đọc hơn.

Dưới đây nên khá hiệu quả.

Thậm chí nhiều hơn nếu cột tên và trọng lượng có thể được INCLUDE-d trong chỉ mục để tránh tra cứu chính.

Nó có thể quét chỉ mục duy nhất theo thứ tự turnvà tính toán tổng số Weightcột đang chạy - sau đó sử dụngLEAD với cùng tiêu chí đặt hàng để xem tổng số chạy trong hàng tiếp theo sẽ là bao nhiêu.

Ngay khi nó tìm thấy hàng đầu tiên trong đó hàng này vượt quá 1000 hoặc là NULL(cho biết không có hàng tiếp theo) thì nó có thể dừng quét.

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 

Kế hoạch thực hiện

nhập mô tả hình ảnh ở đây

Trong thực tế, nó dường như đọc một vài hàng phía trước nơi rất cần thiết - có vẻ như mỗi cặp tổng hợp bộ đệm / luồng cửa sổ khiến hai hàng bổ sung được đọc.

Đối với dữ liệu mẫu trong câu hỏi lý tưởng, nó chỉ cần đọc hai hàng từ quét chỉ mục nhưng trong thực tế, nó đọc 6 nhưng đây không phải là vấn đề hiệu quả đáng kể và nó không làm giảm khi thêm nhiều hàng vào bảng (như trong bản demo này )

Đối với những người quan tâm đến vấn đề này một hình ảnh với các hàng đầu ra bởi mỗi nhà khai thác (như thể hiện bởi các query_trace_column_valuessự kiện mở rộng) là dưới đây, các hàng được xuất ra trong row_idtrật tự (bắt đầu từ 47cho hàng đầu tiên đọc bởi chỉ số quét và kết thúc ở 113cho TOP)

Nhấp vào hình ảnh bên dưới để làm cho nó lớn hơn hoặc thay thế xem phiên bản hoạt hình để làm cho dòng chảy dễ theo dõi hơn .

Tạm dừng hoạt hình tại điểm tổng hợp luồng tay phải đã phát ra hàng đầu tiên (đối với gary - Turn = 1). Dường như rõ ràng là nó đang chờ để nhận được hàng đầu tiên của nó với một WindowCount khác (đối với Jo - Turn = 2). Và bộ đệm cửa sổ không phát hành hàng "Jo" đầu tiên cho đến khi nó đọc hàng tiếp theo với một hàng khácturn (cho thomas - Turn = 3)

Vì vậy, bộ đệm cửa sổ và tổng hợp luồng đều khiến một hàng bổ sung được đọc và có bốn trong số này trong kế hoạch - do đó có 4 hàng bổ sung.

nhập mô tả hình ảnh ở đây

Giải thích về các cột được hiển thị ở trên (dựa trên thông tin ở đây )

  • NodeName: Index Scan, NodeId: 15, Cột Tên: cột bảng cơ sở id được bao phủ bởi chỉ mục
  • NodeName: Index Scan, NodeId: 15, CộtName: biến cột bảng cơ sở được bao phủ bởi chỉ mục
  • NodeName: Clustered Index Seek, NodeId: 17, CộtName: cột bảng cơ sở trọng lượng được lấy từ tra cứu
  • NodeName: Clustered Index Seek, NodeId: 17, CộtName: tên cột bảng cơ sở được lấy từ tra cứu
  • NodeName: Segment, NodeId: 13, CộtName: Segment1010 Trả về 1 khi bắt đầu nhóm mới hoặc null. Như không có Partition Bytrong SUMhàng đầu tiên được 1
  • NodeName: Sequence Project, NodeId: 12, CộtName: RowNumber1009 row_number() trong nhóm được chỉ định bởi cờ Segment1010. Vì tất cả các hàng nằm trong cùng một nhóm, nên số nguyên tăng dần từ 1 đến 6. Sẽ được sử dụng để lọc các hàng khung bên phải trong các trường hợp như rows between 5 preceding and 2 following. (hoặc như LEADsau này)
  • NodeName: Segment, NodeId: 11, CộtName: Segment1011 Trả về 1 khi bắt đầu nhóm mới hoặc null. Vì không có gì Partition Bytrong SUMhàng đầu tiên được 1 (Giống như Segment1010)
  • NodeName: Window Spool, NodeId: 10, Cột Tên: WindowCount1012 Thuộc tính nhóm các hàng với nhau thuộc một khung cửa sổ. Spool cửa sổ này đang sử dụng trường hợp "theo dõi nhanh" cho UNBOUNDED PRECEDING. Nơi nó phát ra hai hàng trên mỗi hàng nguồn. Một với các giá trị tích lũy và một với các giá trị chi tiết. Mặc dù không có sự khác biệt rõ ràng trong các hàng được hiển thị bởi query_trace_column_valuestôi cho rằng các cột tích lũy có trong thực tế.
  • NodeName: Stream Aggregate, NodeId: 9, CộtName: Expr1004 Count(*) được nhóm bởi WindowCount1012 theo kế hoạch nhưng thực tế là số lượng đang chạy
  • NodeName: Stream Aggregate, NodeId: 9, CộtName: Expr1005 SUM(weight) được nhóm bởi WindowCount1012 theo kế hoạch nhưng thực tế là tổng trọng lượng đang chạy (nghĩa là cume_weight)
  • NodeName: Segment, NodeId: 7, CộtName: Expr1002 CASE WHEN [Expr1004]=(0) THEN NULL ELSE [Expr1005] END - Không thấy làm thế nào COUNT(*)có thể là 0 nên sẽ luôn chạy sum ( cume_weight)
  • NodeName: Segment, NodeId: 7, CộtName: Segment1013 Không có partition bytrên LEADhàng đầu tiên được 1. Tất cả còn lại nhận null
  • NodeName: Sequence Project, NodeId: 6, CộtName: RowNumber1006 row_number() trong nhóm được chỉ định bởi cờ Segment1013. Vì tất cả các hàng nằm trong cùng một nhóm, đây là số nguyên tăng dần từ 1 đến 4
  • NodeName: Segment, NodeId: 4, CộtName: bottomRowNumber1008 RowNumber1006 + 1 vì LEADyêu cầu hàng tiếp theo duy nhất
  • NodeName: Segment, NodeId: 4, CộtName: TopRowNumber1007 RowNumber1006 + 1 vì LEADyêu cầu hàng tiếp theo duy nhất
  • NodeName: Segment, NodeId: 4, CộtName: Segment1014 Không partition bytrên LEADhàng đầu tiên được 1. Tất cả còn lại nhận null
  • NodeName: Window Spool, NodeId: 3, Cột Tên: WindowCount1015 Thuộc tính nhóm các hàng với nhau thuộc một khung cửa sổ bằng cách sử dụng các số hàng trước đó. Khung cửa sổ cho LEADcó tối đa 2 hàng (hàng hiện tại và hàng tiếp theo)
  • NodeName: Tập hợp luồng, NodeId: 2, Cột Tên: Expr1003 LAST_VALUE([Expr1002]) choLEAD(cume_weight)

6

Cũng giống như một sự tò mò (vì câu hỏi nêu T-SQL), cũng có thể giải quyết vấn đề này một cách hiệu quả bằng cách sử dụng SQLCLR.

Ý tưởng là đọc từng hàng một lần turncho đến khi weightvượt quá 1000 (hoặc chúng ta hết hàng), sau đó trả về lần nameđọc cuối cùng .

Mã nguồn là:

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;
            }
        }
    }
}

Hàm biên dịch và hàm T-SQL được biên dịch:

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;

Nhận kết quả:

SELECT dbo.Elevator();

1

Biến thể nhẹ từ giải pháp của Martin Smith

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 là khung cửa sổ mặc định nên tôi không khai báo.

Một vị ngữ cho trọng lượng tích lũy hiện tại được sử dụng thay vì trọng lượng tích lũy tiếp theo.

Tôi chưa kiểm tra bất kỳ kế hoạch nào vì vậy tôi không thể biết liệu có sự khác biệt nào trong vấn đề đó không.


Tôi thấy, tôi được bao quanh bởi các chuyên viên máy tính DB :-). Tôi phải kiểm tra tất cả các từ khóa mà các bạn đề cập để nắm bắt những gì họ làm. Tôi chỉ nhìn qua Client statistics --> Total Execution Time, không phải cái Actual execution plannào có lẽ thú vị nhất ở đây. Theo Client Statisticsgiải pháp của bạn thì chậm hơn một chút so với Martin. Cảm ơn thông tin bổ sung. Phương pháp nào có thể được sử dụng để đo lường sự khác biệt hiệu suất giữa các phương pháp khác nhau?
Huyền thoại

1
Tôi e rằng kiến ​​thức về máy chủ SQL của tôi rất hạn chế nên tôi không có nhiều hiểu biết khi sử dụng số liệu nào để sử dụng. Martin có một liên kết db <> fiddle trong câu trả lời của anh ấy, có lẽ bạn có thể xem các kế hoạch ở đó.
Lennart

1
Tôi cũng chưa kiểm tra các kế hoạch nhưng sẽ tưởng tượng rằng điều này có thể sẽ tính tổng chạy trên toàn bộ bảng và sau đó sắp xếp các hàng kết quả khớp với WHERE. Tôi nghi ngờ rằng nó sẽ sử dụng ràng buộc kiểm tra để biết rằng tổng số đang chạy hoàn toàn tăng dần và có thể dừng sớm. Ngoài ra, trong SQL Server, ngoại trừ nơi tổng hợp cửa sổ chế độ hàng loạt được sử dụng chỉ định ROWS thay vì RANGE thì tốt hơn ngay cả khi không có bản sao nào khi bộ đệm cửa sổ nằm trong bộ nhớ không phải là đĩa
Martin Smith

@MartinSmith, thú vị. Trong giải pháp của bạn, LEAD có thể đẩy vị từ next_cume_ weight <10000 bên trong T1 và bảo lãnh sớm từ quá trình quét chỉ mục? Tôi đã kiểm tra kế hoạch cho truy vấn của mình và ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWgiới thiệu một Sequence Project (Compute Scalar)nhà điều hành. Không cần phải nói tôi không biết điều này có nghĩa là gì :-)
Lennart

1
Chỉ mục cung cấp các hàng theo thứ tự cần thiết theo tổng, dẫn và đầu. Ngay khi hàng đầu nhận được hàng đầu tiên, nó có thể ngừng yêu cầu bất kỳ hàng nào nữa và việc thực thi có thể dừng lại.
Martin Smith

0

Bạn có thể tham gia chống lại chính nó:

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 ;

Loại điều này không hiệu quả lắm vì nó gây ra một lựa chọn cho mỗi hàng. Nhưng ít nhất nó được thể hiện như một tuyên bố duy nhất.

Nếu bạn không phải làm điều đó hoàn toàn bằng SQL thì bạn chỉ cần chọn tất cả các hàng và lặp qua chúng, thêm vào khi bạn đi.

Bạn cũng có thể làm tương tự trong một thủ tục được lưu trữ mà không cần bảng tạm thời. Chỉ cần giữ tổng và tên hàng cuối cùng trong một biến.


Xin lỗi, tôi không biết làm thế nào để nó hoạt động với một self-join, nếu bạn có thể làm một ví dụ nhỏ có thể lặp lại, tôi đã thêm định nghĩa bảng vào câu hỏi của mình. Sql của tôi là xấu .... Tôi cần tên của người gần nhất với <= 1000 lbs.
Huyền thoại

Có vẻ như bản cập nhật của bạn hoạt động tốt, bạn sẽ cần phải chỉnh sửa một chút nếu bạn muốn nó chỉ tạo ra đầu ra chính xác. Nhưng như tôi nói, nó không siêu hiệu quả

Đồng ý? Tôi nhận được null cho Người có id 5 ...
Huyền thoại

đó là số lẻ, tôi mong đợi sum () trả về 0 cho tổng số trên 0 hàng

SUM trên 0 hàng không phải là 0 (không may). Bạn cần sử dụng COALESCE()hoặc ISNULL()hàm hoặc CASEbiểu thức để tạo thành 0.
ypercubeᵀᴹ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.