Sorgu çok yavaş çalışıyor, daha da geliştirmenin bir yolu var mı?


9

Aşağıdaki sorgu var ve SUMişlev çağrıları çok nedeniyle , benim sorgu çok yavaş çalışıyor. Veritabanımda çok fazla kayıt var ve her biri için mevcut yıl ve geçen yıldan (Son 30 gün, Son 90 gün ve son 365 gün) bir rapor almak istiyorum:

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

Daha hızlı çalıştırmak için sorgumu nasıl geliştirebileceğim konusunda bir fikrim var mı?

DÜZENLEME: Ben DATEADDişlev çağrısını whereifadeye taşımak ve ilk iki yıl önce yüklemek sonra onları sütunlarda filtre için teşvik edildi , ancak önerilen cevabın yürütüldüğünden ve çalıştığından emin değilim, burada bulunabilir: https: // stackoverflow. com / a / 59944426/12536284

Yukarıdaki çözümü kabul ediyorsanız, lütfen mevcut sorguma nasıl uygulayabileceğimi gösterin.

Sadece FYI, bu SP C #, Entity Framework (DB-First), böyle bir şey kullanıyorum:

var result = MyDBEntities.CalculatorSP();

4
İcra planınızı bize gösterin ...
Dale K

1
Bir şey ON - sorgu yavaş yapabilir ne olduğunu
Fabio


2
Yine, lütfen yürütme planını gönderin.
SQL Police

2
Hala görmüyoruz Execution Plan. Lütfen gönderin
Arun Palanisamy

Yanıtlar:


10

Daha önce de belirtildiği gibi, yürütme planı bu durumda gerçekten yardımcı olacaktır. Gösterdiğiniz şeye bağlı olarak tb1 (a), toplam 15 sütundan 12 sütun çıkardığınız anlaşılıyor , bu nedenle tb1sorgunuzun beklendiği gibi çalışıp çalışmadığını görmek için sorgunuzu herhangi bir birleşim olmadan ve tam karşısında çalıştırmayı deneyebilirsiniz . TOPLA işlev çağrılarınızla ilgili yanlış bir şey göremediğim için, en iyi tahminim, birleştirmelerinizle ilgili bir sorununuz olması, aşağıdakileri yapmanızı öneririm. Geçen mesela katılmak hariç tutarak başlayın edebilir INNER JOIN tb5 e on c.col7 = e.idve benzeri bunun ilgili herhangi kullanımı e.Class as [Class]vee.Classifadesine göre grubunuzda. Bunu tamamen hariç tutmayacağız, bu sadece sorunun bununla olup olmadığından emin olmak için bir testtir, sorgunuz daha iyi çalışırsa ve beklendiği gibi geçici tabloyu son birleştirme yerine geçici bir çözüm olarak kullanmayı deneyebilirsiniz , şöyle bir şey:

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

Aslında, Geçici tablolar SQL Server'da geçici olarak bulunan tablolardır. Geçici tablolar, birden çok kez erişilen anlık sonuç kümelerini depolamak için kullanışlıdır. Bununla ilgili daha fazla bilgiyi burada bulabilirsiniz https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/ Ve burada https://codingsight.com/introduction-to-temporary-tables-in -SQL Server/

Ayrıca şiddetle tavsiye ediyorum size saklı yordam kullanıyorsanız, set NOCOUNTiçin ONağ trafiği büyük ölçüde azalır, çünkü o da önemli bir performans artışı sağlayabilir:

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

Dayanarak bu :

SET NOCOUNT ON, T-SQL sorgu deyimlerinden etkilenen satır sayısını gösteren iletiyi engelleyen bir set deyimidir. Bu, etkilenen satır iletisinin gösterilmesini önlemek için saklı yordamlar ve tetikleyiciler içinde kullanılır. Saklı yordam içinde SET NOCOUNT ON kullanılması saklı yordamın performansını önemli bir farkla artırabilir.


1
Bütününü kopyalama neden lütfen açıklayabilir tb5için #Tempmasa ve hızlı katılmadan daha geçici tablo çalışmalarını katılmadan tb5doğrudan? gerçekte aynı verileri içerirler (ve #Tempeğer mevcutsa bir indeks eksik olabilir tb5). Bu (herkes için ben tüm verileri kopyalamak için daha az verimli olması gerektiğini biliyorum daha verimlidir Gerçekten neden anlayamıyorum ve katılmak).
zig

2
@zig Bu durumda haklısınız, ya da tb5başka bir sunucuda bulunuyorsa? Bu durumda bir geçici tablo kullanmak kesinlikle başka bir sunucuya doğrudan katılmaktan daha hızlıdır. Bu sadece bir şeyin değişip değişmediğini test etmek ve görmek için bir öneriydi Geçmişte benzer bir durumum vardı ve neyse ki geçici tablo OP'nin bu durumda da yardımcı olduğu görülüyor.
Salah Akbari

2

En iyi yaklaşım bir tablo değişkeni / karma tablosuna eklemektir (satır sayısı küçükse bir tablo değişkeni kullanın veya satır sayısı çok büyükse bir karma tablo kullanın). Ardından toplama işlemini güncelleyin ve son olarak tablo değişkeni veya karma tablosundan seçim yapın. Sorgu planına bakmak gereklidir.

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'in büyük bir tablo olduğunu varsayıyorum (tb2, tb3, tb4 ve tb5'e göre).

Öyleyse, bu tablonun seçimini kısıtlamak mantıklıdır (WHERE yan tümcesiyle).

Tb1'in yalnızca küçük bir kısmı kullanılırsa, örneğin tb2, tb3, tb4 ve tb5 ile birleştirmeler gereken satırları yalnızca yüzde birkaçına düşürdüğü için, tabloların birleştirmelerde kullandığınız sütunlarda dizine eklenip eklenmediğini kontrol etmelisiniz. .

Tb1'in büyük bir kısmı kullanılırsa, sonuçlarını tb2, tb3, tb4 ve tb5'e katılmadan önce gruplandırmak mantıklı olabilir. Aşağıda bunun bir örneği var.

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

Önce yürütme planını görmek ve ardından dizin oluşturma ve istatistikleri yeniden oluşturma konusunda karar vermek çok daha iyi olur.
SQL Polisi

Gönderinin neden açıklama yapmadan olumsuz bir puan almasından gerçekten nefret ediyorum. Tabii ki performans sorununun kalbine ulaşmak için yürütme planını incelemek zorunda olduğumu kabul ediyorum. Bunu söyledikten sonra, sorguda ilgili herhangi bir yabancı anahtar için dizinleri kontrol etme konusunda tavsiyem beklemekteyim.
Gert-

1
Bilmeden bir şey "varsayıyorsunuz". Böylece bilinmeyene göre bir cevap gönderirsiniz. Bu nedenle aşağı oy. OP'ye yürütme planını yayınlayarak sorusunu iyileştirmesi talimatını vermek daha iyidir.
SQL Police

Tüm yazdığım bu değil. Şahsen, sadece cevap vermediğimde değil, cevabın kötü ya da yanlış olması durumunda aşağıya vuracağım. Ama cevap verdiğiniz için teşekkürler.
Gert-

Bir bakıma yanlış, çünkü bunun doğru olduğunu nasıl kanıtlayabilirsiniz?
SQL Polisi


0

Bu tür hesaplamaları optimize etmek için bazı değerlerin önceden hesaplanmasını düşünebilirsiniz. Ön hesaplama fikri, okunması veya ilerlemesi gereken satır sayısını azaltmaktır.

Bunu başarmanın bir yolu, dizine alınmış bir görünüm kullanmak ve motoru kendi başına hesaplamalar yapmak üzere bırakmaktır. Bu tür görünümlerin bazı sınırlamaları olduğundan, basit bir tablo oluşturup hesaplamaları yaparsınız. Temel olarak, iş ihtiyaçlarına bağlıdır.

Dolayısıyla, aşağıdaki örnekte RowIDve RowDatetimesütunları içeren bir tablo oluşturuyorum ve 1 milyon satır ekliyorum. Gün başına varlıkları saymak için dizine alınmış bir görünüm kullanıyorum, bu nedenle yılda 1 milyon satırı sorgulamak yerine bu metrikleri saymak için yılda 365 satırı sorgulayacağım.

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

Bu tür bir çözümün başarısı büyük ölçüde verilerin nasıl dağıtıldığına ve kaç satıra sahip olduğunuza bağlıdır. Örneğin, yılın her günü için günde bir girişiniz varsa, görünüm ve tablo aynı satır eşleşmesine sahip olur, bu nedenle G / Ç işlemleri azalmaz.

Ayrıca, yukarıdaki sadece verilerin gerçekleştirilmesi ve okunması için bir örnektir. Sizin durumunuzda, görünüm tanımına daha fazla sütun eklemeniz gerekebilir.


0

DatesId bir dizin ile verilerime katılmak için bir arama tablosu "Tarihler" tablosu kullanırsınız. Tarihsel verilere göz atmak istediğimde tarihleri ​​filtre olarak kullanıyorum. Birleştirme hızlıdır ve bu nedenle DatesId kümelenmiş birincil dizin (birincil anahtar) olarak filtreleme yapar. Veri tablonuz için de tarih sütununu (dahil edilen sütun olarak) ekleyin.

Tarihler tablosunda aşağıdaki sütunlar bulunur:

Tarihler, Tarih, Yıl, Çeyrek, YılKeyrek, AyNum, AyAdı Kısa, YılAğır, HaftaNum, GünOfYear, GünOfMonth, GünNumOfWeek, GünAdı

Örnek veriler: 20310409 2031-04-09 2031 2 2031-Q2 4 Nisan Nisan 2031_15 15 99 9 3 Çarşamba

Veritabanına aktarabilmeniz için bunun bir csv'sini istiyorsanız bana PM yapabilirsiniz, ancak eminim ki çevrimiçi olarak böyle bir şey bulabilir ve kendiniz yapabilirsiniz.

Her tarih için bir tamsayı alabilmeniz için bir kimlik sütunu da ekliyorum. Bu, çalışmayı biraz daha kolaylaştırır, ancak bir gereklilik değildir.

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

Bu kolayca belirli bir döneme atlamamı sağlıyor. Bu konuda kendi görüşlerinizi oluşturmak oldukça kolaydır. Elbette bunu yıllarca, haftalarca vb. Yapmak için ROW_NUMBER () işlevini kullanabilirsiniz.

İstediğim tarihe sahip olduğumda verilere katılıyorum. Çok hızlı çalışır!


0

Değerleri her zaman tam ay sayısına göre grupladığınız için, ilkinden aygıta göre bir alt sorguda gruplandırırım. Bu geçici bir tablo kullanmaya benzer. Bunun sorgunuzu gerçekten hızlandıracağından emin değilim.

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 sorgusunun hızını artırmak için dizinler eklemeniz gerekir. Birleştirilmiş her tablo için bir dizin eklemeniz gerekir.

Oracle için bu kod örneği gibi:

CREATE INDEX supplier_idx
ON supplier (supplier_name);

bu kötü bir öneri değil. OP'den bir dizin tablosu olmadan bir geçici tablo oluşturulduğunu görürsünüz - INNER JOIN #Temp e üzerinde c.col7 = e.id. cevapta iyileştirme için yer olsa da, toplu olarak indirilmesi gerektiğini sanmıyorum. özellikle yeni bir kullanıcı için.
smoore4

@ smoore4 Kabul ediyorum, açık bir argüman olmadan bu aşağı oylama seçeneği kaldırılmalıdır. Bu işlevin büyük bir yanlış kullanımı var
Greggz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.