แบบสอบถามกำลังดำเนินการช้ามากมีวิธีใดปรับปรุงเพิ่มเติมหรือไม่


9

ฉันมีคิวรีต่อไปนี้และเนื่องจากมีSUMการเรียกใช้ฟังก์ชันจำนวนมากเคียวรีของฉันจึงทำงานช้าเกินไป ฉันมีบันทึกจำนวนมากในฐานข้อมูลของฉันและฉันต้องการรับรายงานจากปีปัจจุบันและปีที่แล้ว (30 วันล่าสุด 90 วันล่าสุดและ 365 วันสุดท้าย) สำหรับแต่ละคน:

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 30 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 30 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 90 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 90 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 365 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 365 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 30 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 30 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 90 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 90 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 365 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 365 Days Col2]


    FROM 
    tb1 a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    tb5 e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

ใครบ้างมีความคิดใด ๆ ฉันจะปรับปรุงแบบสอบถามของฉันเพื่อให้ทำงานได้เร็วขึ้นได้อย่างไร

แก้ไข:ฉันได้รับการสนับสนุนให้ย้ายการDATEADDเรียกใช้ฟังก์ชันไปที่whereคำสั่งและโหลดสองปีแรกก่อนจากนั้นกรองพวกเขาในคอลัมน์ แต่ฉันไม่แน่ใจว่าคำตอบที่แนะนำนั้นได้รับการดำเนินการและทำงานแล้วสามารถพบได้ที่นี่: https: // stackoverflow ดอทคอม / a / 59944426/12536284

หากคุณเห็นด้วยกับวิธีการแก้ปัญหาข้างต้นโปรดแสดงให้ฉันเห็นว่าฉันจะนำไปใช้ในการสืบค้นปัจจุบันได้อย่างไร

เพียงแค่ FYI ฉันใช้ SP นี้ใน C #, Entity Framework (DB-First) บางสิ่งเช่นนี้:

var result = MyDBEntities.CalculatorSP();

4
แสดงแผนการดำเนินการของคุณให้เราทราบ ...
Dale K

1
ทำทุกอย่าง - เป็นสิ่งที่ทำให้คิวรีช้า
Fabio


2
อีกครั้งโปรดโพสต์แผนการดำเนินการ
ตำรวจ SQL

2
Execution Planเรายังคงไม่ได้เห็น กรุณาโพสต์มัน
อรุณ Palanisamy

คำตอบ:


10

ตามที่ได้รับการกล่าวถึงไปแล้วแผนการดำเนินการจะมีประโยชน์จริง ๆ ในกรณีนี้ ขึ้นอยู่กับสิ่งที่คุณแสดงดูเหมือนว่าคุณได้แยกคอลัมน์ 12 คอลัมน์จากทั้งหมด 15 คอลัมน์tb1 (a)ดังนั้นคุณสามารถลองเรียกใช้คิวรีโดยไม่ต้องเข้าร่วมและตรงข้ามกับtb1เพื่อดูว่าคิวรีของคุณทำงานได้ตามที่คาดหวังหรือไม่ เนื่องจากฉันไม่เห็นอะไรผิดปกติกับการเรียกใช้ฟังก์ชัน SUM ของคุณการคาดเดาที่ดีที่สุดของฉันคือคุณมีปัญหากับการเข้าร่วมของคุณฉันขอแนะนำให้ทำดังต่อไปนี้ คุณสามารถเริ่มต้นได้โดยไม่รวมการเข้าร่วมครั้งล่าสุด INNER JOIN tb5 e on c.col7 = e.idและการใช้งานที่เกี่ยวข้องใด ๆ เช่นe.Class as [Class]และe.Classในกลุ่มของคุณโดยคำสั่ง เราจะไม่แยกออกทั้งหมดนี่เป็นเพียงการทดสอบเพื่อให้แน่ใจว่าปัญหานั้นเกิดขึ้นจริงหรือไม่หากแบบสอบถามของคุณทำงานได้ดีขึ้นและเป็นไปตามที่คาดไว้คุณสามารถลองใช้ตารางชั่วคราวเป็นวิธีแก้ปัญหาแทนการเข้าร่วมครั้งล่าสุด บางอย่างเช่นนี้:

SELECT *
INTO #Temp
FROM
  (
     select * from tb5
  ) As tempTable;

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]

    -- SUM Functions

FROM 
    tb1 a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    #Temp e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

ที่จริงแล้ว Temporary tables เป็นตารางที่มีอยู่ชั่วคราวบน SQL Server ตารางชั่วคราวมีประโยชน์สำหรับการจัดเก็บชุดผลลัพธ์ทันทีที่เข้าถึงได้หลายครั้ง คุณสามารถอ่านเพิ่มเติมได้ที่นี่https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/ และนี่https://codingsight.com/introduction-to-temporary-tables-in -SQL เซิร์ฟเวอร์ /

นอกจากนี้ผมจะขอแนะนำถ้าคุณกำลังใช้ขั้นตอนการเก็บการตั้งค่าNOCOUNTไปONก็ยังสามารถให้เพิ่มประสิทธิภาพการทำงานอย่างมีนัยสำคัญเนื่องจากเครือข่ายการจราจรจะลดลงมาก:

SET NOCOUNT ON
SELECT *
INTO #Temp
-- The rest of code

ขึ้นอยู่กับสิ่งนี้ :

SET NOCOUNT ON เป็นชุดคำสั่งที่ป้องกันข้อความที่แสดงจำนวนแถวที่ได้รับผลกระทบจากคำสั่งแบบสอบถาม T-SQL ใช้ในขั้นตอนการจัดเก็บและทริกเกอร์เพื่อหลีกเลี่ยงการแสดงข้อความแถวที่ได้รับผลกระทบ การใช้ SET NOCOUNT ON ภายในโพรซีเดอร์ที่เก็บไว้สามารถปรับปรุงประสิทธิภาพของโพรซีเดอร์ที่เก็บไว้ได้ด้วยกำไรขั้นต้นที่สำคัญ


1
คุณช่วยอธิบายได้ไหมว่าทำไมการคัดลอกทั้งหมดtb5ไปที่#Tempโต๊ะและเข้าร่วมตารางชั่วคราวทำงานได้เร็วกว่าการเข้าร่วมtb5โดยตรง แน่นอนว่าพวกเขามีข้อมูลเดียวกัน (และ#Tempอาจจะหายไปดัชนีถ้ามันมีอยู่ในtb5) ฉันไม่เข้าใจจริงๆว่าเพราะเหตุใดจึงมีประสิทธิภาพมากกว่า (สำหรับทั้งหมดที่ฉันรู้ว่าควรมีประสิทธิภาพน้อยกว่าในการคัดลอกข้อมูลทั้งหมดและเข้าร่วม)
ซิกแซ

2
@zig คุณถูกต้องในกรณีนี้ แต่ถ้าtb5อยู่ในเซิร์ฟเวอร์อื่นล่ะ ในกรณีนี้การใช้ตารางชั่วคราวจะเร็วกว่าการเข้าร่วมโดยตรงกับเซิร์ฟเวอร์อื่นอย่างแน่นอน นั่นเป็นเพียงข้อเสนอแนะเพื่อทดสอบและดูว่ามีอะไรเปลี่ยนแปลงหรือเปล่าที่ฉันเคยมีสถานการณ์คล้ายกันในอดีตและดูเหมือนว่าโชคดีที่ตารางอุณหภูมิได้ช่วย OP ในกรณีนี้ด้วย
Salah Akbari

2

วิธีที่ดีที่สุดคือการแทรกลงในตัวแปรตาราง / ตารางแฮช (หากจำนวนแถวมีขนาดเล็กใช้ตัวแปรตารางหรือใช้ตารางแฮชหากจำนวนแถวมีขนาดใหญ่มาก) จากนั้นอัพเดตการรวมและจากนั้นเลือกจากตัวแปรตารางหรือตารางแฮช การค้นหาแผนแบบสอบถามเป็นสิ่งที่จำเป็น

DECLARE @MYTABLE TABLE (ID INT, [Title] VARCHAR(500), [Class] VARCHAR(500),
[Current - Last 30 Days Col1] INT, [Current - Last 30 Days Col2] INT,
[Current - Last 90 Days Col1] INT,[Current - Last 90 Days Col2] INT,
[Current - Last 365 Days Col1] INT, [Current - Last 365 Days Col2] INT,
[Last year - Last 30 Days Col1] INT, [Last year - Last 30 Days Col2] INT,
[Last year - Last 90 Days Col1] INT, [Last year - Last 90 Days Col2] INT,
[Last year - Last 365 Days Col1] INT, [Last year - Last 365 Days Col2] INT)



INSERT INTO @MYTABLE(ID, [Title],[Class], 
[Current - Last 30 Days Col1], [Current - Last 30 Days Col2],
[Current - Last 90 Days Col1], [Current - Last 90 Days Col2],
[Current - Last 365 Days Col1], [Current - Last 365 Days Col2],
[Last year - Last 30 Days Col1], [Last year - Last 30 Days Col2],
[Last year - Last 90 Days Col1], [Last year - Last 90 Days Col2],
[Last year - Last 365 Days Col1], [Last year - Last 365 Days Col2]
  )
SELECT    b.id  ,d.[Title] ,e.Class ,0,0,0,0,0,0,0,0,0,0,0,0        
FROM     tb1 a
INNER JOIN   tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN   tb3 c on b.fid = c.col5
INNER JOIN   tb4 d on c.id = d.col6
INNER JOIN  tb5 e on c.col7 = e.id
GROUP BY b.id, d.Title, e.Class

UPDATE T 
SET [Current - Last 30 Days Col1]=K.[Current - Last 30 Days Col1] , 
[Current - Last 30 Days Col2]    =K.[Current - Last 30 Days Col2],
[Current - Last 90 Days Col1]    = K.[Current - Last 90 Days Col1], 
[Current - Last 90 Days Col2]    =K.[Current - Last 90 Days Col2] ,
[Current - Last 365 Days Col1]   =K.[Current - Last 365 Days Col1], 
[Current - Last 365 Days Col2]   =K.[Current - Last 365 Days Col2],
[Last year - Last 30 Days Col1]  =K.[Last year - Last 30 Days Col1],
 [Last year - Last 30 Days Col2] =K.[Last year - Last 30 Days Col2],
[Last year - Last 90 Days Col1]  =K.[Last year - Last 90 Days Col1], 
[Last year - Last 90 Days Col2]  =K.[Last year - Last 90 Days Col2],
[Last year - Last 365 Days Col1] =K.[Last year - Last 365 Days Col1],
 [Last year - Last 365 Days Col2]=K.[Last year - Last 365 Days Col2]
    FROM @MYTABLE T JOIN 
     (
SELECT 
    b.id as [ID]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 30 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 30 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 90 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 90 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 365 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 365 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 30 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 30 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 90 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 90 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 365 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 365 Days Col2]
    FROM     tb1 a
INNER JOIN   tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN   tb3 c on b.fid = c.col5
INNER JOIN   tb4 d on c.id = d.col6
INNER JOIN  tb5 e on c.col7 = e.id
GROUP BY    b.id
) AS K ON T.ID=K.ID


SELECT *
FROM @MYTABLE

0

ฉันถือว่า tb1 เป็นตารางขนาดใหญ่ (เทียบกับ tb2, tb3, tb4 และ tb5)

ถ้าเป็นเช่นนั้นมันสมเหตุสมผลที่นี่เพื่อ จำกัด การเลือกของตารางนั้น (ด้วยส่วนคำสั่ง WHERE)

หากใช้เพียงส่วนเล็ก ๆ ของ tb1 ตัวอย่างเช่นเนื่องจากการรวมกับ tb2, tb3, tb4 และ tb5 ลดแถวที่ต้องการเป็นเพียงไม่กี่เปอร์เซ็นต์คุณควรตรวจสอบว่าตารางนั้นถูกทำดัชนีในคอลัมน์ที่คุณใช้ในการรวมหรือไม่ .

หากใช้งาน tb1 เป็นส่วนใหญ่สามารถทำการจัดกลุ่มผลลัพธ์ก่อนเข้าร่วมกับ tb2, tb3, tb4 และ tb5 ด้านล่างเป็นตัวอย่างของสิ่งนั้น

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]
    ,SUM(a.[Current - Last 30 Days Col1]) AS [Current - Last 30 Days Col1]
    ,SUM(a.[Current - Last 30 Days Col2]) AS [Current - Last 30 Days Col2]
    ,SUM(a.[Current - Last 90 Days Col1]) AS [Current - Last 90 Days Col1]
    -- etc.
    FROM (
      SELECT a.id, a.col3

      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 30 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 30 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 90 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 90 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 365 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 365 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 30 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 30 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 90 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 90 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 365 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 365 Days Col2]

      FROM  tb1 a
      WHERE a.DateCol >= DATEADD(YEAR,-2,GETDATE())
      GROUP BY a.id, a.col3
    ) AS a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    tb5 e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

มันจะดีกว่าที่จะดูแผนการดำเนินการก่อนแล้วจึงตัดสินใจสร้างดัชนีและสร้างสถิติใหม่
ตำรวจ SQL

ฉันเกลียดที่โพสต์ของฉันได้รับคะแนนลบโดยไม่มีคำอธิบายว่าทำไม แน่นอนฉันเห็นด้วยที่จะได้รับหัวใจของปัญหาประสิทธิภาพหนึ่งมีการตรวจสอบแผนการดำเนินการ ต้องบอกว่าฉันยืนตามคำแนะนำของฉันเกี่ยวกับการตรวจสอบดัชนีสำหรับคีย์ต่างประเทศใด ๆ ที่เกี่ยวข้องในแบบสอบถาม
Gert-

1
คุณ "สมมติ" บางสิ่งโดยไม่ทราบ ดังนั้นคุณโพสต์คำตอบบนพื้นฐานของความไม่รู้จัก ดังนั้นการลงคะแนน ดีกว่าที่จะสั่งให้ OP ปรับปรุงคำถามของเขาโดยโพสต์แผนการดำเนินการ
ตำรวจ SQL

นั่นไม่ใช่ทั้งหมดที่ฉันเขียน โดยส่วนตัวแล้วฉันจะ downvote เท่านั้นหากคำตอบนั้นไม่ถูกต้องหรือไม่ผิดเมื่อฉันไม่เห็นด้วย แต่ขอบคุณสำหรับการตอบสนอง
Gert-

ในทางที่ผิดเพราะคุณสามารถพิสูจน์ได้ว่าถูกต้อง?
ตำรวจ SQL


0

สำหรับการเพิ่มประสิทธิภาพการคำนวณคุณต้องพิจารณาการคำนวณค่าล่วงหน้าบางอย่าง แนวคิดของการคำนวณล่วงหน้าคือการลดจำนวนแถวที่จำเป็นต้องอ่านหรือดำเนินการต่อ

วิธีหนึ่งในการบรรลุเป้าหมายนี้คือการใช้มุมมองที่มีการจัดทำดัชนีและปล่อยให้เครื่องยนต์ทำการคำนวณด้วยตัวเอง เนื่องจากมุมมองประเภทนี้มีข้อ จำกัด คุณสามารถสร้างตารางอย่างง่ายและทำการคำนวณแทน โดยทั่วไปจะขึ้นอยู่กับความต้องการทางธุรกิจ

ดังนั้นในตัวอย่างด้านล่างฉันกำลังสร้างตารางด้วยRowIDและRowDatetimeคอลัมน์และแทรก 1 ล้านแถว ฉันใช้มุมมองที่มีการจัดทำดัชนีเพื่อนับเอนทิตีต่อวันดังนั้นแทนที่จะค้นหา 1 ล้านแถวต่อปีฉันจะค้นหา 365 แถวต่อปีเพื่อนับเมตริกเหล่านี้

DROP TABLE IF EXISTS [dbo].[DataSource];
GO

CREATE TABLE [dbo].[DataSource]
(
    [RowID] BIGINT IDENTITY(1,1) PRIMARY KEY
   ,[RowDateTime] DATETIME2
);

GO

DROP VIEW IF EXISTS [dbo].[vw_DataSource];
GO

CREATE VIEW [dbo].[vw_DataSource] WITH SCHEMABINDING
AS
SELECT YEAR([RowDateTime]) AS [Year]
      ,MONTH([RowDateTime]) AS [Month]
      ,DAY([RowDateTime]) AS [Day]
      ,COUNT_BIG(*) AS [Count]
FROM [dbo].[DataSource]
GROUP BY YEAR([RowDateTime])
        ,MONTH([RowDateTime])
        ,DAY([RowDateTime]);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_vw_DataSource] ON [dbo].[vw_DataSource]
(
    [Year] ASC,
    [Month] ASC,
    [Day] ASC
);

GO

DECLARE @min bigint, @max bigint
SELECT @Min=1 ,@Max=1000000

INSERT INTO [dbo].[DataSource] ([RowDateTime])
SELECT TOP (@Max-@Min+1) DATEFROMPARTS(2019,  1.0 + floor(12 * RAND(convert(varbinary, newid()))), 1.0 + floor(28 * RAND(convert(varbinary, newid())))          )       
FROM master..spt_values t1 
CROSS JOIN master..spt_values t2

GO


SELECT *
FROM [dbo].[vw_DataSource]


SELECT SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(MONTH,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 30 Days Col1]
      ,SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(QUARTER,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 90 Days Col1]
      ,SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(YEAR,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 365 Days Col1]
FROM [dbo].[vw_DataSource];

ความสำเร็จของการแก้ปัญหาดังกล่าวขึ้นอยู่กับว่ามีการกระจายข้อมูลอย่างไรและคุณมีแถวกี่แถว ตัวอย่างเช่นหากคุณมีหนึ่งรายการต่อวันในแต่ละวันของปีมุมมองและตารางจะมีการจับคู่แถวเดียวกันดังนั้นการดำเนินการ I / O จะไม่ลดลง

นอกจากนี้ข้างต้นเป็นเพียงตัวอย่างของการทำให้ข้อมูลเป็นจริงและอ่านมัน ในกรณีของคุณคุณอาจต้องเพิ่มคอลัมน์เพิ่มเติมในการกำหนดมุมมอง


0

ฉันจะใช้ตารางการค้นหา "วันที่" เพื่อเข้าร่วมข้อมูลของฉันกับดัชนีใน DatesId ฉันใช้วันที่เป็นตัวกรองเมื่อฉันต้องการเรียกดูข้อมูลประวัติ การเข้าร่วมนั้นรวดเร็วและดังนั้นจึงเป็นตัวกรองเนื่องจาก DatesId เป็นดัชนีหลักคลัสเตอร์ (คีย์หลัก) เพิ่มคอลัมน์วันที่ (รวมคอลัมน์) สำหรับตารางข้อมูลของคุณเช่นกัน

ตารางวันที่มีคอลัมน์ต่อไปนี้:

DatesId, วันที่, ปี, ไตรมาส, YearQuarter, MonthNum, MonthNameShort, YearWeek, WeekNum, DayOfYear, DayOfMonth, DayNumOfWeek, DayName

ข้อมูลตัวอย่าง: 20310409 2031-04-09 2031 2 2031-Q2 4 เมษายน เม.ย. 2031_15 15 99 9 3 วันพุธ

คุณสามารถ PM ​​ฉันถ้าคุณต้องการ csv ของสิ่งนี้เพื่อให้คุณสามารถนำเข้าสู่ฐานข้อมูล แต่ฉันแน่ใจว่าคุณสามารถหาบางสิ่งเช่นนี้ออนไลน์และสร้างของคุณเองได้อย่างง่ายดาย

ฉันเพิ่มคอลัมน์ข้อมูลประจำตัวด้วยเพื่อที่คุณจะได้จำนวนเต็มในแต่ละวัน สิ่งนี้ทำให้การทำงานกับง่ายขึ้นเล็กน้อย แต่ไม่ใช่ข้อกำหนด

SELECT * FROM dbo.dates where dateIndex BETWEEN (getDateIndexDate(getDate())-30 AND getDateIndexDate(getDate())+0) --30 days ago

สิ่งนี้ทำให้ฉันสามารถย้อนกลับไปยังช่วงเวลาหนึ่งได้อย่างง่ายดาย การสร้างมุมมองของคุณเองนั้นค่อนข้างง่าย แน่นอนคุณสามารถใช้ฟังก์ชัน ROW_NUMBER () เพื่อทำสิ่งนี้เป็นเวลาหลายปีหลายสัปดาห์ ฯลฯ ได้เช่นกัน

เมื่อฉันมี daterange ที่ฉันต้องการฉันจะเข้าร่วมกับข้อมูล ทำงานได้เร็วมาก!


0

เนื่องจากคุณมักจะจัดกลุ่มค่าตามจำนวนเดือนทั้งหมดฉันจะจัดกลุ่มตามเดือนในแบบสอบถามย่อยตามข้อ คล้ายกับการใช้ตารางชั่วคราว ไม่แน่ใจว่าสิ่งนี้จะเพิ่มความเร็วการสืบค้นของคุณหรือไม่

SELECT f.id, f.[Title], f.Class,
    SUM(CASE WHEN f.MonthDiff = 1 THEN col1 ELSE 0 END) as [Current - Last 30 Days Col1],
    -- etc
FROM (
    SELECT 
        b.id,
        d.[Title],
        e.Class,
        DateDiff(Month, a.DateCol, GETDATE()) as MonthDiff,
        Sum(a.col1) as col1,
        Sum(a.col2) as col2
    FROM  tb1 a
    INNER JOIN tb2 b on a.id = b.fid and a.col3 = b.col4
    INNER JOIN tb3 c on b.fid = c.col5
    INNER JOIN tb4 d on c.id = d.col6
    INNER JOIN tb5 e on c.col7 = e.id
    WHERE a.DateCol between DATEADD(YEAR,-2,GETDATE() and GETDATE()
    GROUP BY b.id, d.Title, e.Class, DateDiff(Month,  a.DateCol, GETDATE())
) f
group by f.id, f.[Title], f.Class

-2

เพื่อปรับปรุงความเร็วของแบบสอบถาม SQL คุณต้องเพิ่มดัชนี สำหรับแต่ละตารางที่รวมคุณต้องเพิ่มหนึ่งดัชนี

เช่นตัวอย่างรหัสนี้สำหรับ oracle:

CREATE INDEX supplier_idx
ON supplier (supplier_name);

นี่ไม่ใช่ข้อเสนอแนะที่ไม่ดี คุณเห็นจาก OP ว่ามีการสร้างตารางชั่วคราวโดยไม่มีดัชนี - เข้าร่วม #Temp e บน c.col7 = e.id ในขณะที่มีห้องพักสำหรับการปรับปรุงในคำตอบฉันไม่คิดว่ามันควรจะเป็น downvoted en masse โดยเฉพาะอย่างยิ่งสำหรับผู้ใช้ใหม่
smoore4

@ smoore4 เห็นด้วยตัวเลือกการ downvoting นี้โดยไม่มีอาร์กิวเมนต์ที่ชัดเจนควรถูกลบออก มีการใช้ฟังก์ชันนี้ในทางที่ผิดอย่างมาก
Greggz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.