একটি বিশাল টেবিলের আদেশকৃত কলামে সর্বশেষ নাল মানটি কীভাবে পাবেন?


13

আমার কাছে নিম্নলিখিত ইনপুট রয়েছে:

 id | value 
----+-------
  1 |   136
  2 |  NULL
  3 |   650
  4 |  NULL
  5 |  NULL
  6 |  NULL
  7 |   954
  8 |  NULL
  9 |   104
 10 |  NULL

আমি নিম্নলিখিত ফলাফল আশা করি:

 id | value 
----+-------
  1 |   136
  2 |   136
  3 |   650
  4 |   650
  5 |   650
  6 |   650
  7 |   954
  8 |   954
  9 |   104
 10 |   104

তুচ্ছ সমাধানটি কোনও টেবিলের সাথে কোনও <সম্পর্কের সাথে যুক্ত হবে এবং তারপরে একটিতে MAXমানটি নির্বাচন করবে GROUP BY:

WITH tmp AS (
  SELECT t2.id, MAX(t1.id) AS lastKnownId
  FROM t t1, t t2
  WHERE
    t1.value IS NOT NULL
    AND
    t2.id >= t1.id
  GROUP BY t2.id
)
SELECT
  tmp.id, t.value
FROM t, tmp
WHERE t.id = tmp.lastKnownId;

তবে এই কোডটির তুচ্ছ সঞ্চালন ইনপুট টেবিলের সারিগুলির গণনা ( O (n ^ 2) ) অভ্যন্তরীণভাবে স্কোয়ার তৈরি করবে । আমি টি-স্কুএলটিকে এটিকে অনুকূল করে তোলার প্রত্যাশা করেছি - একটি ব্লক / রেকর্ড স্তরে, কাজটি করা খুব সহজ এবং লিনিয়ার, মূলত লুপের জন্য ( ও (এন) )।

তবে, আমার পরীক্ষা-নিরীক্ষায়, সর্বশেষতম এমএস এসকিউএল 2016 এই কোয়েরিকে সঠিকভাবে অনুকূলিত করতে পারে না, এই কোয়েরিটিকে বড় ইনপুট টেবিলের জন্য কার্যকর করা অসম্ভব করে তুলেছে।

তদ্ব্যতীত, ক্যোয়ারীটি দ্রুত চালাতে হবে, একইভাবে সহজ (তবে খুব আলাদা) কার্সার-ভিত্তিক সমাধানটি অনিবার্য।

কিছু মেমরি-ব্যাকড অস্থায়ী টেবিল ব্যবহার করা একটি ভাল আপস হতে পারে তবে আমি নিশ্চিত নই যে এটি উপকারীগুলি ব্যবহার করে আমার উদাহরণের ক্যোয়ারীটি কার্যকর হয়নি বলে বিবেচনা করে তা দ্রুততরভাবে চালানো যায় কিনা।

আমি টি-স্কিএল ডক্স থেকে কিছু উইন্ডোংয়ের ফাংশনটিও সন্ধান করতে চাইছি, আমি যা চাই তা করতে ট্রিক করা যায়। উদাহরণস্বরূপ, संचयी যোগফল খুব একই রকম কিছু করছে, তবে আমি সর্বশেষের অ-নাল উপাদান দেওয়ার জন্য এটি চালাকি করতে পারি না, এবং এর আগে উপাদানের যোগফলটি না দিয়ে।

আদর্শ সমাধানটি প্রক্রিয়াগত কোড বা অস্থায়ী সারণী ছাড়াই একটি দ্রুত ক্যোয়ারী হবে। বিকল্পভাবে, অস্থায়ী টেবিলগুলি সহ একটি সমাধানও ঠিক আছে, তবে প্রক্রিয়াগতভাবে সারণির পুনরাবৃত্তি করা এটি নয়।

উত্তর:


12

এই ধরণের সমস্যার একটি সাধারণ সমাধান ইটজিক বেন-গান তার নিবন্ধে দ্য লাস্ট অ ননলুল ধাঁধা :

DROP TABLE IF EXISTS dbo.Example;

CREATE TABLE dbo.Example
(
    id integer PRIMARY KEY,
    val integer NULL
);

INSERT dbo.Example
    (id, val)
VALUES
    (1, 136),
    (2, NULL),
    (3, 650),
    (4, NULL),
    (5, NULL),
    (6, NULL),
    (7, 954),
    (8, NULL),
    (9, 104),
    (10, NULL);

SELECT
    E.id,
    E.val,
    lastval =
        CAST(
            SUBSTRING(
                MAX(CAST(E.id AS binary(4)) + CAST(E.val AS binary(4))) OVER (
                    ORDER BY E.id
                    ROWS UNBOUNDED PRECEDING),
            5, 4)
        AS integer)
FROM dbo.Example AS E
ORDER BY
    E.id;

ডেমো: ডিবি <> ফিডাল


11

আমি টি-স্কুএলটিকে এটিকে অনুকূল করে তোলার প্রত্যাশা করেছি - একটি ব্লক / রেকর্ড স্তরে, কাজটি করা খুব সহজ এবং লিনিয়ার, মূলত লুপের জন্য (ও (এন))।

আপনি লিখেছেন এমন কোয়েরি নয়। এটি টেবিল স্কিমাটির কিছুটা ছোটখাটো বিবরণের উপর নির্ভর করে আপনি লিখেছেন এমন প্রশ্নের ক্যোয়ারের সমতুল্য নাও হতে পারে। আপনি ক্যোয়ারী অপ্টিমাইজার থেকে খুব বেশি আশা করছেন।

ডান সূচকের সাহায্যে আপনি নিম্নলিখিত টি-এসকিউএল এর মাধ্যমে যে অ্যালগরিদমটি পেয়েছেন তা পেতে পারেন:

SELECT t1.id, ca.[VALUE] 
FROM dbo.[BIG_TABLE(FOR_U)] t1
CROSS APPLY (
    SELECT TOP (1) [VALUE]
    FROM dbo.[BIG_TABLE(FOR_U)] t2
    WHERE t2.ID <= t1.ID AND t2.[VALUE] IS NOT NULL
    ORDER BY t2.ID DESC
) ca; --ORDER BY t1.ID ASC

প্রতিটি সারির জন্য, ক্যোয়ারী প্রসেসর সূচকটি পিছনের দিকে ঘুরিয়ে দেয় এবং যখন এটির জন্য একটি নাল মান সহ একটি সারি খুঁজে পায় তখন থামে [VALUE]। আমার মেশিনে এটি উত্স সারণীতে 100 মিলিয়ন সারিগুলির জন্য প্রায় 90 সেকেন্ডের মধ্যে শেষ হয় । ক্যোয়ারী প্রয়োজনীয়তার চেয়ে বেশি সময় ধরে চলেছে কারণ ক্লায়েন্টের সমস্ত সারিটি বাতিল করে কিছু সময় ব্যয় করা হয়।

আপনার যদি অর্ডার করা ফলাফলের প্রয়োজন হয় বা এত বড় ফলাফল সেট নিয়ে আপনি কী পরিকল্পনা করছেন তা আমার কাছে পরিষ্কার নয়। আসল পরিস্থিতি মেটাতে ক্যোয়ারী সামঞ্জস্য করা যেতে পারে। এই পদ্ধতির সর্বাধিক সুবিধা হ'ল এর জন্য ক্যোয়ারী পরিকল্পনায় কোনও ধরণের প্রয়োজন হয় না। এটি বৃহত্তর ফলাফলের সেটগুলির জন্য সহায়তা করতে পারে। একটি অসুবিধা হ'ল টেবিলে প্রচুর NULL উপস্থিত থাকলে পারফরম্যান্স অনুকূল হবে না কারণ অনেকগুলি সারি সূচক থেকে পড়বে এবং ফেলে দেওয়া হবে। ফিল্টারড সূচক যা আপনার ক্ষেত্রে NUL গুলি বাদ দেয় তার সাথে আপনার পারফরম্যান্স উন্নত করতে সক্ষম হওয়া উচিত।

পরীক্ষার জন্য নমুনা তথ্য:

DROP TABLE IF EXISTS #t;

CREATE TABLE #t (
ID BIGINT NOT NULL
);

INSERT INTO #t WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);

DROP TABLE IF EXISTS dbo.[BIG_TABLE(FOR_U)];

CREATE TABLE dbo.[BIG_TABLE(FOR_U)] (
ID BIGINT NOT NULL,
[VALUE] BIGINT NULL
);

INSERT INTO dbo.[BIG_TABLE(FOR_U)] WITH (TABLOCK)
SELECT 10000 * t1.ID + t2.ID, CASE WHEN (t1.ID + t2.ID) % 3 = 1 THEN t2.ID ELSE NULL END
FROM #t t1
CROSS JOIN #t t2;

CREATE UNIQUE CLUSTERED INDEX ADD_ORDERING ON dbo.[BIG_TABLE(FOR_U)] (ID);

7

এক পদ্ধতি, ব্যবহার করে OVER()এবং MAX()এবং COUNT()এর উপর ভিত্তি করে এই উৎস হতে পারে:

SELECT ID, MAX(value) OVER (PARTITION BY Value2) as value
FROM
(
    SELECT ID, value
        ,COUNT(value) OVER (ORDER BY ID) AS Value2
    FROM dbo.HugeTable
) a
ORDER BY ID;

ফলাফল

Id  UpdatedValue
1   136
2   136
3   650
4   650
5   650
6   650
7   954
8   954
9   104
10  104

এই উত্সের উপর ভিত্তি করে আরেকটি পদ্ধতি , প্রথম উদাহরণের সাথে ঘনিষ্ঠভাবে সম্পর্কিত

;WITH CTE As 
( 
SELECT  value,
        Id, 
        COUNT(value) 
        OVER(ORDER BY Id) As  Value2 
FROM dbo.HugeTable
),

CTE2 AS ( 
SELECT Id,
       value,
       First_Value(value)  
       OVER( PARTITION BY Value2
             ORDER BY Id) As UpdatedValue 
FROM CTE 
            ) 
SELECT Id,UpdatedValue 
FROM CTE2;

3
"বিশাল টেবিল" দিয়ে এই পদ্ধতিগুলি কীভাবে সম্পাদন করে সে সম্পর্কে বিশদ যুক্ত করার বিষয়ে বিবেচনা করুন।
জো ওবিশ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.