Hej OK, beskriv gärna vad du har (vilka tabeller och värden) och vad du vill ha tag på. Oj, inte konstigt om det går långsamt. Jag håller med Mikael, koden behöver skrivas om rejält, så tala om vad du försöker göra. Som redan har sagts tror jag också att en helt annan lösning är den med #temp tabeller vore bäst. Ok Hur bygger jag bort detta bäst Du kan jämföra värdet i tabellen med sig självt om användaren inte valt något:Skulle behöva hjälp med att få denna procedur snabbare!
Jag har skrivit denna procedur problemet nu är att den är för långsam. Har försökt få den bättre. Skulle vara tacksam för all hjälp.
use fir
go
create procedure dbo.P_MatrisVarde_SelPR
(
@Where varchar(800)
)
as
BEGIN
SET NOCOUNT ON
Begin
CREATE TABLE #tmpResult (idmatris int, aktuellperiod char(10), period char(10), idvariabel int, namn char(50), varde int)
--Lägger dit ett index
CREATE INDEX I_Index ON dbo.#tmpResult
(idmatris, aktuellperiod, period, idvariabel, namn, varde)
EXEC('INSERT INTO #tmpResult (idmatris, aktuellperiod, period, idvariabel, namn, varde)
SELECT MV.IdMatris, M.AktuellPeriod, MV.Period, MV.IdVariabel, V.Namn, MV.Varde
FROM MatrisVarde MV
JOIN Matris M
ON M.IdMatris = MV.IdMatris
JOIN Variabel V
ON MV.IdVariabel = V.IdVariabel '
+ @WHERE +
'ORDER BY MV.IdVariabel, MV.IdMatris DESC')
--Loopar igenom variabel för variabel för att kolla att den finns för alla idmatriser
DECLARE @idvariabel int,
@idmatris int,
@varde1 int,
@varde2 int,
@diff int,
@diffprocent int,
@grans int
SET @varde1 = -1
SET @varde2 = -1
SET @grans = (SELECT GransStorRevidering FROM Parametervarden
WHERE AktuellPeriod = (SELECT DISTINCT AktuellPeriod FROM #tmpResult))
CREATE TABLE #tmpFinalresult (idmatris int, aktuellperiod char(10), period char(10),idvariabel int, namn char(50), varde int, diff int, diffprocent int)
--Lägger dit ett index
CREATE INDEX I_Index ON dbo.#tmpFinalresult
(idmatris, aktuellperiod, period, idvariabel, namn, varde, diff, diffprocent)
DECLARE variabel_cursor CURSOR FOR
SELECT DISTINCT idvariabel FROM #tmpResult ORDER BY idvariabel DESC
OPEN variabel_cursor
FETCH NEXT FROM variabel_cursor
INTO @idvariabel
--Loopar variabler
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE idmatris_cursor CURSOR FOR
SELECT DISTINCT idmatris FROM #tmpResult ORDER BY idmatris ASC
OPEN idmatris_cursor
FETCH NEXT FROM idmatris_cursor
INTO @idmatris
--Loopar matriser
WHILE @@FETCH_STATUS = 0
BEGIN
IF exists(SELECT 1 FROM #tmpResult WHERE idmatris = @idmatris AND idvariabel=@idvariabel)
BEGIN
SET @varde1 = (SELECT varde FROM #tmpResult WHERE idmatris = @idmatris AND idvariabel = @idvariabel)
END
ELSE
BEGIN
--Sätter in en rad för idmatris idvariabel som inte finns
SET @varde1 = 0
END
IF @varde2 = -1
BEGIN
--Kod om det är den första post som inte har någon att jämföras med SET @diffprocent = 0
END
ELSE
BEGIN
SET @diff = 0
SET @diffprocent = 0
IF @varde1 <> 0 OR @varde2 <> 0
BEGIN
--Kod för att beräkna diff
SET @diff = (@varde1-@varde2)
IF @varde2 <> 0
BEGIN
SET @diffprocent = ((@diff*0.1)/(@varde2*0.1)*100.0)
END
ELSE
BEGIN
SET @diffprocent = 100
END
END
ELSE
BEGIN
SET @diff = 0
SET @diffprocent = 0
END
IF @diffprocent <> 0
BEGIN
INSERT INTO #tmpFinalresult (idmatris, aktuellperiod, period, idvariabel, namn, varde, diff, diffprocent)
SELECT idmatris, aktuellperiod, period, idvariabel, namn, varde, @diff, @diffprocent
FROM #tmpResult
WHERE idmatris = @idmatris AND idvariabel = @idvariabel
END
END
SET @varde2 = @varde1
FETCH NEXT FROM idmatris_cursor
INTO @idmatris
END
SET @varde2 = -1
CLOSE idmatris_cursor
DEALLOCATE idmatris_cursor
FETCH NEXT FROM variabel_cursor
INTO @idvariabel
END
CLOSE variabel_cursor
DEALLOCATE variabel_cursor
--Väljer det som skickas upp till applikationen
SELECT idmatris, aktuellperiod, period, idvariabel, namn, varde, diff, diffprocent FROM #tmpFinalresult WHERE diffprocent >= @grans ORDER BY IdVariabel, IdMatris DESC
DROP TABLE #tmpResult
DROP TABLE #tmpFinalresult
End
ENDSv: Skulle behöva hjälp med att få denna procedur snabbare!
Jag fattar att den inte är snabb, men den behöver inte snabbas upp, utan skrivas om.
/mickeSv: Skulle behöva hjälp med att få denna procedur snabbare!
Det är inte helt otänkbart att det skulle gå att få ut resultatet med en enda fråga, utan temporära tabeller och allting, vilket skulle gå oerhört mycket snabbare.
Det finns ju visserligen vissa saker i koden som går att förbättra, till exempel den här koden:
IF exists(SELECT 1 FROM #tmpResult WHERE idmatris = @idmatris AND idvariabel=@idvariabel)
BEGIN
SET @varde1 = (SELECT varde FROM #tmpResult WHERE idmatris = @idmatris AND idvariabel = @idvariabel)
END
ELSE
BEGIN
--Sätter in en rad för idmatris idvariabel som inte finns
SET @varde1 = 0
END
kan du göra om till:
SET @varde1 = 0
SELECT @varde1 = varde FROM #tmpResult WHERE idmatris = @idmatris AND idvariabel = @idvariabel
Sv: Skulle behöva hjälp med att få denna procedur snabbare!
Några tips bara..
Testa att byta ut temptabelen till en Table-variabel:
declare @TmpList table (ID int IDENTITY, RadNr int)
Du skapar ett stort index över flera kolumner i din temp-tabell..
Behöver du index på allt? för mycket index segar ner inserts.
Du ska självklart ha index på det som du villkorar på!
EXEC ('variabel SQL')
är alltid en nackdel. Försök bygga bort det.
"Loopar igenom variabel för variabel "
Farligt.. dåligt.. försök tänka i mängder och joins i stället.... ?
SELECT DISTINCT AktuellPeriod
AktuellPeriod är förstås INDEXERAD?? :)
SELECT DISTINCT idmatris
idmatris indexerad?
AND idvariabel = @idvariabel
idvariabel indexerad?
(indexera kolumnerna var för sig... Create index..)
WHERE diffprocent >= @grans ORDER BY IdVariabel, IdMatris DESC
indexera diffprocent Sv:Skulle behöva hjälp med att få denna procedur snabbare!
Skall försöka förklara
Tabellerna jag har är dessa
TABLE Matris
IdMatris numeric(15, 0) IDENTITY (1, 1) NOT NULL ,
AktuellPeriod varchar (10) NOT NULL ,
IdStatus varchar (10) NULL ,
Kommentar varchar (255) NULL ,
UppdatDatum datetime NULL ,
UppdatAnvandare varchar (30) NULL ,
StatusNr char (3) NULL ,
TABLE MatrisVarde
IdMatris T_IdMatris NOT NULL ,
Period varchar (10) NOT NULL ,
IdMedlemKonto T_IdMedlem NOT NULL ,
IdMedlemSektor T_IdMedlem NOT NULL ,
IdMedlemKontopost T_IdMedlem NOT NULL ,
IdMedlemMotsektor T_IdMedlem NOT NULL ,
IdMedlemKontoslag T_IdMedlem NOT NULL ,
MatrisTyp char (1) NULL ,
IdVariabel T_IdVariabel NULL ,
Varde T_Varde NULL ,
ValtFranKontoslag T_IdMedlem NULL ,
UppdatDatum T_UppdatDatum NULL ,
UppdatAnvandare T_UppdatAnvandare NULL ,
TABLE Variabel
IdVariabel T_IdVariabel IDENTITY (1, 1) NOT NULL ,
IdMedlemKonto T_IdMedlem NULL ,
ExtIdKonto T_ExtId NULL ,
IdMedlemSektor T_IdMedlem NULL ,
ExtIdSektor T_ExtId NULL ,
IdMedlemKontoslag T_IdMedlem NULL ,
ExtIdKontoslag T_ExtId NULL ,
IdMedlemKontopost T_IdMedlem NULL ,
ExtIdKontopost T_ExtId NULL ,
IdMedlemMotsektor T_IdMedlem NULL ,
ExtIdMotsektor T_ExtId NULL ,
Namn varchar (255) NULL ,
KortNamn varchar (40) NULL ,
GiltigFrom varchar (10) NULL ,
GiltigTom varchar (10) NULL ,
UppdatDatum T_UppdatDatum NULL ,
UppdatAnvandare T_UppdatAnvandare NULL ,
De jag först gör är att plockar ut uppgifterna från tabellerna som anv har valt i formuläret och stoppar in i en temp tabell.
CREATE TABLE #tmpResult (idmatris int, aktuellperiod char(10), period char(10), idvariabel int, namn char(50), varde int)
--Lägger dit ett index
CREATE INDEX I_Index ON dbo.#tmpResult
(idmatris, aktuellperiod, period, idvariabel, namn, varde)
EXEC('INSERT INTO #tmpResult (idmatris, aktuellperiod, period, idvariabel, namn, varde)
SELECT MV.IdMatris, M.AktuellPeriod, MV.Period, MV.IdVariabel, V.Namn, MV.Varde
FROM MatrisVarde MV
JOIN Matris M
ON M.IdMatris = MV.IdMatris
JOIN Variabel V
ON MV.IdVariabel = V.IdVariabel '
+ @WHERE +
'ORDER BY MV.IdVariabel, MV.IdMatris DESC')
Resultatet i den tabellen borde se ut som nedan.
IDmatris Variabel Värde
172 431 100
175 431 50
216 431 40
172 522 100
216 522 50
Sedan skall jag för varje variabell loppa igenom alla idmatriser och se om kombinationen finns, finns den spar man värdet för den raden annars sätter man värdet till 0. Sedan vid nästa lopp skall det värde man får fram jämföras med föregående värde som man har sparat undan.
tex
172 431 jämförs med 175 431
men
172 522 skall inte jämföras med 216 522 utan måste jämföras med 0
Diffen räknas ut i både värde och % resultatet stoppas in i en ny temp tabell
Sist väljs de värden ut som överstiger @grans som plockas fram tidigare.
Resultatet skall bli enligt nedan
IDmatris Variabel Värde Diff% Diffvärde
172 431 100 100% 50
172 522 100 100% 50
Hoppas beskrivningen räcker
/Joakim
Sv:Skulle behöva hjälp med att få denna procedur snabbare!
EXEC('INSERT INTO #tmpResult (idmatris, aktuellperiod, period, idvariabel, namn, varde)
SELECT MV.IdMatris, M.AktuellPeriod, MV.Period, MV.IdVariabel, V.Namn, MV.Varde
FROM MatrisVarde MV
JOIN Matris M
ON M.IdMatris = MV.IdMatris
JOIN Variabel V
ON MV.IdVariabel = V.IdVariabel '
+ @WHERE +
'ORDER BY MV.IdVariabel, MV.IdMatris DESC')
Vill ha så att where satsen byggs dynamiskt beroende på vad användaren väljer
Koden i vb.net ser ut så här
'Skapar den dynamiska Where-satsen
sqlWhere = "WHERE ( MV.Period = '" + Period + "'"
If Konto <> "" Then
sqlWhere = sqlWhere & " AND MV.IdMedlemKonto = '" + CStr(Konto) + "'"
End If
If Sektor <> "" Then
sqlWhere = sqlWhere & " AND MV.IdMedlemSektor = '" + CStr(Sektor) + "'"
End If
If Kontoslag <> 0 Then
sqlWhere = sqlWhere & " AND MV.IdMedlemKontoslag = '" + CStr(Kontoslag) + "'"
End If
sqlWhere = sqlWhere & ") "
/Joakim
Sv: Skulle behöva hjälp med att få denna procedur snabbare!
WHERE MV.Period = @Period
AND MV.IdMedlemKonto = ISNULL(@Konto, MV.IdMedlemKonto)
AND MV.IdMedlemSektor = ISNULL(@Sektor, MV.IdMedlemSektor)
AND MV.IdMedlemKontoslag = ISNULL(@Kontoslag, MV.IdMedlemKontoslag)