en-USsv-SE

Active Forums

PrevPrev Go to previous topic
NextNext Go to next topic
Last Post 05 Jan 2016 04:26 PM by  JAhlen
SQLug.se Challenge 2015
 48 Replies
Sort:
You are not authorized to post a reply.
Page 2 of 3 << < 123 > >>
Author Messages
SwePeso
New Member
New Member
Posts: 67


--
09 Nov 2015 08:16 AM

Posted By Daniel Hutmacher on 2015-10-30 01:24
Så om en giv slutar (dvs får en statuskod) på kort 415, dvs näst sista kortet i blandningen; används då kort nr 416 till att börja på en ny hand, eller börjar man om på kort 417, alltså på nästa blandning?

Ja, kort 416 ges till givaren och alla åtta lekarna blandas och sedan fortsätter man med att ge givaren kort nummer 2 i den omgången.
SwePeso
New Member
New Member
Posts: 67


--
09 Nov 2015 08:18 AM

Posted By Markus Jägerskogh on 2015-11-06 12:04
För att haka på Daniels fråga lite:
Om man ska börja om räknandet efter varje blandning; ska man då räkna så långt det går i varje blandning, eller ska man alltid förkasta några av de sista korten (tydligen brukar man på casinon samla in alla kort och blanda om när man börjar närma sig slutet av högen med tillgängliga kort)?

Jag funderade på det i den här tävlingen och även att ta med att kunna splitta korten men till slut valde jag att hålla tävlingen lite enklare och inte fullt så komplext.
Inga kort ska förkastas.
SwePeso
New Member
New Member
Posts: 67


--
09 Nov 2015 08:19 AM

Posted By Micke on 2015-10-30 02:29
Vore kul om man kunde använda CTP 3 istället. En del nya saker där som skulle kunna vara användbart. JSON, check constraints på inmem tabeller . Är det aktuellt med ett byte av version av SQL Server?

Tävlingen kommer att köras på den senaste officiella versionen av SQL Server 2016 och den är just nu CTP 3.0
Androd
New Member
New Member
Posts: 3


--
11 Nov 2015 12:58 PM
Kommer några "mellantids"-resultat att redovisas så som ni gjorde förra året?
JAhlen
Veteran Member
Veteran Member
Posts: 144


--
12 Nov 2015 09:49 AM
Hej! Nu har vi förtydligat reglerna på tävlingens hemsida:

Givaren måste stanna/hålla när poängsumman visar 17, 18, 19 eller 20. Om det finns flera möjliga poängsummor (på grund av ess) så måste givaren stanna om någon av poängsummorna hamnar i intervallet 17-20 (eller 21 eftersom det då blir vinst).

Som Peter skrivit så kommer också testerna att köras på senaste officiella versionen av SQL Server 2016.

MVH
Johan
JAhlen
Veteran Member
Veteran Member
Posts: 144


--
12 Nov 2015 09:50 AM

Posted By Androd on 2015-11-11 12:58
Kommer några "mellantids"-resultat att redovisas så som ni gjorde förra året?


Ja, vi planerar att redovisa resultat så snart vi fått in lite fler tävlingssvar.

MVH
Johan
SwePeso
New Member
New Member
Posts: 67


--
17 Nov 2015 02:43 PM

Posted By Androd on 2015-11-11 12:58
Kommer några "mellantids"-resultat att redovisas så som ni gjorde förra året?

Ja, senast på torsdag kommer jag att redovisa ställningen, liknande föregående år.
JAhlen
Veteran Member
Veteran Member
Posts: 144


--
19 Nov 2015 09:45 AM
Nu är en första omgång testresultat publicerade. Obs att bara de tävlingsbidrag som fått godkänt visas.

MVH
Johan
JAhlen
Veteran Member
Veteran Member
Posts: 144


--
26 Nov 2015 01:45 PM
Hej!

Nu är en ny omgång resultat publicerade. Testkörningarna gjordes den 24:e november.

Obs att bara godkända bidrag visas. Om en tävlande har skickat in flera bidrag så visas bara det bästa.

MVH
Johan
JAhlen
Veteran Member
Veteran Member
Posts: 144


--
27 Nov 2015 03:53 PM
Hej!
Ett förtydligande om hur testerna går till. Vi provkör varje bidrag ett antal gånger. Varje provkörning följer följande steg:
1. RESTORE görs på databasen
2. Setup-scriptet körs
3. Klockan startar
4. Lösnings-scriptet körs
5. Klockan stoppas och vi mäter tiden

MVH
Johan
Jonas
New Member
New Member
Posts: 13


--
01 Dec 2015 08:14 AM
Tack för en rolig tävling! Nu väntar jag med spänning på resultatet.

Jag hoppas att jag åtminstone löste uppgiften.
Mitt första skiss med en cursor tog 1 min 20 sekunder, mitt tredje bidrag med memory optimized tables tog 4 sekunder, så jag lite har jag lärt mig av att jobba med tävlingsuppgiften.
Karfunkel
New Member
New Member
Posts: 11


--
04 Dec 2015 12:23 PM
Tyvärr blev det en vanlig memory optimized för mig med. Jag gjorde även en MO-procedur avsedd att exekveras parallellt, och försökte göra en ripoff (med vissa förenklingar - tinyint i st f XML, inga WarmUpMessages) på förra årets vinnande bidrag med Message Broker, men jag fick inte Message Broker att lira boll.
Jag får ligga i hårdträning till nästa år
Daniel Hutmacher
New Member
New Member
Posts: 17


--
10 Dec 2015 12:05 AM
Grattis, Sergey, till segern i årets tävling! Jag är väldigt nyfiken på hur du löste uppgiften dubbelt så effektivt som jag.
Daniel Hutmacher
New Member
New Member
Posts: 17


--
10 Dec 2015 07:30 AM
En kort sammanfattning av mitt bidrag:

* Jag laddar en in-memory-tabell med alla kort, men för att få bättre prestanda skapar jag den i form av char(8000)-blobbar med 8000 kort åt gången (ett tecken motsvarar valören på ett kort). Färre rader i en INSERT verkar ge bättre prestanda.
* De här char(8000)-blobbarna skapar jag som sträng-konkateneringar med FOR XML PATH('')
* Jag använder CROSS APPLY och trace flag 8649 för att få till en väldigt effektiv parallellism i detta steg.
* Sedan kör jag en native-procedur mot in-memory-tabellen som räknar ut statuskoderna. Dessa lagras sedan i likadana 8000 tecken långa strängar, som sedan skrivs till en utdata-tabell.
* Den prestandamässigt jobbigaste biten visade sig vara att uppdatera statuskoden i dbo.CardHistory, och det var den här delen jag la absolut mest energi på att försöka optimera. Den här operationen stod för nästan 90% av körtiden.

En mer ingående post (på engelska förvisso) som beskriver min lösning finns här: http://sqlsunday.com/2015/12/10/the...challenge/

Setup-scriptet:
IF (OBJECT_ID(&#39;dbo.CalculateCardHistory_8k&#39;) IS NOT NULL)
	DROP PROCEDURE dbo.CalculateCardHistory_8k;
GO
IF (EXISTS (SELECT NULL FROM sys.types WHERE [name]=&#39;CardHistory_8k_type&#39;))
	DROP TYPE dbo.CardHistory_8k_type;
GO
IF (OBJECT_ID(&#39;dbo.CardHistory_8k&#39;) IS NOT NULL)
	DROP TABLE dbo.CardHistory_8k;
GO

CREATE TABLE dbo.CardHistory_8k (
	CardID		int NOT NULL,
	Cards		char(8000) COLLATE Finnish_Swedish_100_BIN2 NOT NULL,
	PRIMARY KEY NONCLUSTERED (CardID)
) WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_ONLY);

GO
CREATE TYPE dbo.CardHistory_8k_type AS TABLE (
	CardID		int NOT NULL,
	Cards		char(8000) COLLATE Finnish_Swedish_100_BIN2 NOT NULL,
	PRIMARY KEY NONCLUSTERED (CardID)
) WITH (MEMORY_OPTIMIZED=ON);

GO
CREATE PROCEDURE dbo.CalculateCardHistory_8k
	@s		int OUTPUT,
	@l		int OUTPUT,
	@w		int OUTPUT,
	@b		int OUTPUT,
	@tbl	dbo.CardHistory_8k_type READONLY
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS

BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL=SERIALIZABLE, LANGUAGE=&#39;us_english&#39;, DELAYED_DURABILITY=ON);

	DECLARE @CardID int=1, @count int, @rank tinyint=0, @score tinyint=0, @cards tinyint=0,
			@str char(8000)=&#39;&#39;, @ace bit=0, @status char(1)=&#39; &#39;, @offset smallint=1,
			@result varchar(8000)=&#39;&#39;, @ch char(1);

	WHILE (@str IS NOT NULL) BEGIN;

		SET @str=NULL;

		SELECT @str=Cards, @offset=1, @result=&#39;&#39;
		FROM @tbl WHERE CardID=@CardID;

		WHILE (@offset<=8000 AND @str IS NOT NULL) BEGIN;

			SET @ch=SUBSTRING(@str, @offset, 1);
			IF (@ch!=&#39;&#39;) BEGIN;
				SELECT @cards=@cards+1, @rank=CAST(@ch AS tinyint);

				IF (@rank=0) SET @rank=10;
				ELSE IF (@rank=1) SET @ace=1;

				SET @score=@score+@rank;

				IF (@score>=17 OR @ace=1 AND @score BETWEEN 7 AND 11) BEGIN;
					IF (@score>=17 AND @score<21 OR @ace=1 AND @score>=7 AND @score<11) SELECT @status=&#39;S&#39;, @s=@s+1;
					ELSE IF (@score>21) SELECT @status=&#39;L&#39;, @l=@l+1;
					ELSE IF ((@score=21 OR @score=11 AND @ace=1) AND @cards>2) SELECT @status=&#39;W&#39;, @w=@w+1;
					ELSE IF (@score=11 AND @ace=1 AND @cards=2) SELECT @status=&#39;B&#39;, @b=@b+1;

					SELECT @score=0, @cards=0, @ace=0, @result=@result+@status;
				END;
				ELSE SET @result=@result+&#39;_&#39;;
			END;

			SELECT @CardID=@CardID+1, @offset=@offset+1;
		END;

		IF (@str IS NOT NULL)
			INSERT INTO dbo.CardHistory_8k (CardID, Cards)
			VALUES (@CardID-8000, @result);
	END;
END;

GO


... och lösningsscriptet:
SET NOCOUNT ON;

BEGIN TRANSACTION;

	DECLARE @s int=0, @l int=0, @w int=0, @b int=0,
	        @offset int=1, @cards char(8000), @CardCount int;

	CREATE TABLE #temp (
		CardID		int NOT NULL,
		Cards		char(8000) COLLATE Finnish_Swedish_100_BIN2 NOT NULL,
		PRIMARY KEY CLUSTERED (CardID)
	);

	CREATE TABLE #batches (
		CardID		int NOT NULL,
		PRIMARY KEY CLUSTERED (CardID)
	);

	SET @CardCount=(SELECT MAX(CardID) FROM dbo.CardHistory);

	--- Vi anv&#228;nder #batches-tabellen f&#246;r att kunna skapa en parallell
	--- CROSS APPLY-l&#246;sning. Tabellvariabler och in-memory-tabeller g&#229;r
	--- inte att parallellisera, s&#229; det blir en helt vanlig temptabell.
	WITH cte AS (
		SELECT 1 AS CardID UNION ALL
		SELECT CardID+8000 FROM cte WHERE CardID+8000<@CardCount)
	INSERT INTO #batches (CardID)
	SELECT CardID FROM cte
	OPTION (MAXRECURSION 0);

	--- Och av samma anledning mellanlagrar vi str&#228;ngblobbarna i en
	--- vanlig temptabell f&#246;r att sedan lyfta &#246;ver dem i en in-
	--- memory-tabellvariabel.
	INSERT INTO #temp (CardID, Cards)
	SELECT b.CardID, CAST(x.Cards AS char(8000)) AS Cards
	FROM #batches AS b
	CROSS APPLY (
		SELECT (CASE WHEN h2.[Rank]<10 THEN h2.[Rank] ELSE 0 END)
		FROM dbo.CardHistory AS h2
		WHERE h2.CardID>=b.CardID AND h2.CardID<b.CardID+8000
		ORDER BY h2.CardID
		FOR XML PATH(&#39;&#39;), TYPE) AS x(Cards)
	--- Trace flag f&#246;r att tvinga parallellism, eftersom fr&#229;gan annars
	--- blir "f&#246;r billig" och k&#246;rs seriellt trots v&#229;r vackra nested
	--- loop/apply-pattern.
	OPTION (QUERYTRACEON 8649);

	DECLARE @tbl dbo.CardHistory_8k_type;

	INSERT INTO @tbl (CardID, Cards)
	SELECT CardID, Cards FROM #temp;

	--- ... och skicka in allt i proceduren:
	EXECUTE dbo.CalculateCardHistory_8k
		@s=@s OUTPUT, @l=@l OUTPUT, @w=@w OUTPUT, @b=@b OUTPUT, @tbl=@tbl;

	--- Processa utdatan:
	WHILE (1=1) BEGIN;
		--- H&#228;mta en 8000 tecken l&#229;ng textstr&#228;ng, char(8000):
		SELECT @cards=Cards
		FROM dbo.CardHistory_8k WITH (SERIALIZABLE)
		WHERE CardID=@offset;

		IF (@@ROWCOUNT=0) BREAK;

		--- ... och UPDATE&#39;a in den i dbo.CardHistory:
		UPDATE dbo.CardHistory
		SET [Status]=SUBSTRING(@cards, CardID+1-@offset, 1)
		WHERE CardID>=@offset AND CardID<@offset+8000 AND
		      SUBSTRING(@cards, CardID+1-@offset, 1)!=&#39;_&#39;;

		SET @offset=@offset+8000;
	END;

	--- Uppdatera dbo.DealerStatus:
	TRUNCATE TABLE dbo.DealerStatus;

	INSERT INTO dbo.DealerStatus
	VALUES (&#39;B&#39;, @b), (&#39;L&#39;, @l),
		   (&#39;S&#39;, @s), (&#39;W&#39;, @w);

COMMIT TRANSACTION WITH (DELAYED_DURABILITY=ON);

--DROP TABLE #batches;
--DROP TABLE #temp;


Jättespänd på att få se era lösningar!
Jonas
New Member
New Member
Posts: 13


--
10 Dec 2015 08:24 AM
Grattis, Sergey! Alltid imponerande och se era lösningar, jag lär mig mycket på det. Kan ni publicera hela resultatlistan? Jag vill gärna veta om jag åtminstone hade en korrekt lösning!

Min lösning bygger också på att ladda en in-memory-tabell och en native-procedure (utan alla andra trix Daniel gjort). Framför allt fick jag lära mig allt man inte får göra i en native-procedur (tex. fick jag byta ut alla mina case satser mot if)

---Jonas Claudelin, Hypergene, 2015-11-29
---SQL SM 2015 - THREE --
--SETUP Script

if object_id('dbo.Run') Is not null drop procedure dbo.Run
go
if object_id('dbo.CardHistory2') is not null drop table dbo.CardHistory2
go
if object_id('dbo.resultat') is not null drop table dbo.resultat
go

---alla kort till tabell i minnet
CREATE TABLE dbo.CardHistory2 (
[CardID] INT not null PRIMARY KEY NONCLUSTERED,
[Rank] [tinyint] NOT NULL
) WITH (MEMORY_OPTIMIZED=ON, durability = schema_only)
GO
--sparar status på kort där det finns en status
CREATE TABLE dbo.resultat (
[CardID] INT not null PRIMARY KEY NONCLUSTERED,
[Status] int NOT NULL
) WITH (MEMORY_OPTIMIZED=ON, durability = schema_only)
GO


CREATE PROCEDURE dbo.Run
@CountB int output, @CountL int output,@CountS int output, @CountW int output
with native_compilation,schemabinding, execute as owner
as
begin atomic with (transaction isolation level = snapshot, language = N'us_english', delayed_durability = on)

---Deklarerar variabler
DECLARE @CardID INT --Rullande id på rad i loopen
DECLARE @SumA int = 0 --eventuella ess = 1
DECLARE @SumB int = 0 --eventuella Ess = 11
DECLARE @Status int=-1 ---X = giv ej avgjord ännu
DECLARE @Rank int --Värde på raden i loopen
DECLARE @AntalkortIgive int=0 ---för att hålla koll på om blackjack

---Använder int istället för char(1) som status pga. native_compilation
--'B' = 100
--'L' = 200
--'S' = 300
--'W' = 400

---Första kortet
SELECT @CardID = [CardID],@Rank = [Rank]
FROM dbo.CardHistory2
WHERE [CardID]=1

SET @CountB = 0
SET @CountL = 0
SET @CountS = 0
SET @CountW = 0

WHILE @@rowcount > 0
BEGIN

IF @RANK>10 --Alla klädda kort räknas som 10
BEGIN
SET @RANK=10
END

SET @AntalkortIgive=@AntalkortIgive+1

IF @Rank<>1 ---Draget kort är EJ ESS
BEGIN
--B
IF (@SumA+@RANK=21 AND @AntalkortIgive=2) begin SET @Status=100 end --en av måste uppfyllas
IF (@SumB+@RANK=21 AND @AntalkortIgive=2) begin SET @Status=100 end
--W
IF (@SumA+@RANK=21 AND @AntalkortIgive<>2 ) begin SET @Status=400 end --en av måste uppfyllas
IF (@SumB+@RANK=21 AND @AntalkortIgive<>2 ) begin SET @Status=400 end
--L
IF (@SumA+@RANK>21 AND @SumB+@RANK>21) begin SET @Status = 200 end --båda måste var 'L'
--S
IF (@SumA+@RANK>16 AND @SumA+@RANK<21) begin SET @Status = 300 end --en av måste uppfyllas
IF (@SumB+@RANK>16 AND @SumB+@RANK<21) begin SET @Status = 300 end
END --End @Rank<>1

IF @Rank=1 --Draget kort är ett Ess
BEGIN
--Sätt Ess flagga
--SET @GiveMedEss=1

IF @SumA+11 > 21
BEGIN
IF @SumA+1>16 begin SET @Status=300 end --S övriga alternativ ej applicerbara
END
ELSE
BEGIN
IF @SumA+11 = 21 AND @AntalkortIgive=2 begin SET @Status=100 end --B
IF @SumA+11 = 21 AND @AntalkortIgive<>2 begin SET @Status=400 end --W
IF @SumA+11 > 16 AND @SumA+11 <> 21 begin SET @Status= 300 end --S
END
END --End @Rank=1

IF @Status=-1 --Given ej avslutad, räkna upp summa-varibler
BEGIN
SET @SumA=@SumA+@RANK --Ess = 1

IF @Rank=1 --Hanterar Ess
BEGIN
IF @SumB+11>21 BEGIN SET @SumB=@SumB+1 END
ELSE BEGIN SET @SumB=@SumB+11 END
END
ELSE
BEGIN
SET @SumB=@SumB+@Rank
END

END --End @Status=-1

IF @Status<>-1 ---SENASTE KORTET GAV RESULTAT, Given avslutas
BEGIN
---Sparar status i temptabell
INSERT INTO dbo.resultat ([CardID],[Status])
VALUES (@CardID,@Status)

---Räknar antal Deals per typ av resultat
IF @Status=100 BEGIN SET @CountB = @CountB+1 END
IF @Status=200 BEGIN SET @CountL = @CountL+1 END
IF @Status=300 BEGIN SET @CountS = @CountS+1 END
IF @Status=400 BEGIN SET @CountW = @CountW+1 END

--Nolleställer inför ny giv
SET @Status=-1
SET @SumA=0
SET @SumB=0
SET @AntalkortIgive=0
END --End @Status<>-1

----NÄSTA KORT
SET @CardID = @CardID + 1

SELECT @Rank = [Rank]
FROM dbo.CardHistory2
WHERE [CardID]=@CardID
END --END WHILE-LOOP

--RETUNERA RESULTAT
SELECT @CountB,@CountL,@CountS,@CountW

End; --slut sp
GO
---Slut Setup

---Jonas Claudelin, Hypergene, 2015-11-29
---SQL SM 2015 - THREE --
--Lösnings-script

--Fyll MEMORY_OPTIMIZED tabell
INSERT INTO dbo.CardHistory2 (CardID,[Rank])
SELECT CardID,[Rank] FROM dbo.CardHistory

--Tömm tabell
TRUNCATE TABLE [dbo].[DealerStatus]

DECLARE @CountB int = 0
DECLARE @CountL int = 0
DECLARE @CountS int = 0
DECLARE @CountW int = 0

---Kör procedure
EXECUTE dbo.Run @CountB=@CountB output, @CountL=@CountL output,@CountS=@CountS output, @CountW=@CountW output

---Uppdatera DealerStatus
insert into [dbo].[DealerStatus]
select 'B',@CountB
union all
select 'L',@CountL
union all
select 'S',@CountS
union all
select 'W',@CountW

---Uppdaterar [dbo].[CardHistory] med status
UPDATE C
SET [Status]=CASE WHEN T.[Status]=100 THEN 'B'
WHEN T.[Status]=200 THEN 'L'
WHEN T.[Status]=300 THEN 'S'
WHEN T.[Status]=400 THEN 'W'
END
FROM [dbo].[CardHistory] C
INNER JOIN dbo.resultat T
ON C.CardID=t.CardID

---Klart!
Daniel Hutmacher
New Member
New Member
Posts: 17


--
10 Dec 2015 11:03 AM
Jonas (och eventuella andra intressenter), här är det script jag använde för att validera att min lösning räknar rätt.
En korrekt lösning ska generera genomgående tomma resultatset (utom sista, där istället diff-kolumnen ska vara noll).

--- Alla givar summerar till korrekt statuskod?
SELECT TOP 10 *
FROM (
SELECT StartCardID AS [From], EndCardID AS [To], [count], [Status],
(CASE WHEN val+10*Ace=21 AND [count]=2 THEN 'B'
WHEN 21 IN (val, val+10*Ace) THEN 'W'
WHEN 10*Ace+val BETWEEN 17 AND 20 OR
val BETWEEN 17 AND 20 THEN 'S'
WHEN val>21 THEN 'L' ELSE '' END) AS [Correct status],
ISNULL(CAST((CASE WHEN val>=17 THEN val END) AS varchar(10)) ,'') AS [Score excl aces],
ISNULL(CAST((CASE WHEN val>=7 AND val<=11 AND Ace=1 THEN val+10*Ace END) AS varchar(10)), '') AS [Score w/aces]
FROM (
SELECT StartCardID, MAX(CardID) AS EndCardID, MAX(CardID)+1-StartCardID AS [count],
SUM(r) AS val, MAX((CASE WHEN r=1 THEN 1 ELSE 0 END)) AS Ace,
MAX(NULLIF([Status], '')) AS [Status]
FROM (
SELECT CardID, [Status], (CASE WHEN [Rank]<10 THEN [Rank] ELSE 10 END) AS r,
1+ISNULL(MAX((CASE WHEN [Status]!='' THEN CardID ELSE 0 END)) OVER (ORDER BY CardID ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) AS StartCardID
FROM dbo.CardHistory
-- WHERE CardID<=1000
) AS sub
GROUP BY StartCardID
) AS sub2
) AS sub3
WHERE [Status]!=[Correct status]
ORDER BY [From];


--- De kort som "blir över" på slutet räcker inte till någon statuskod?
SELECT * FROM (
SELECT SUM((CASE WHEN [Rank]=1 THEN 11 WHEN [Rank]<10 THEN [Rank] ELSE 10 END)) AS Score
FROM dbo.CardHistory
WHERE CardID>(
SELECT MAX(CardID)
FROM dbo.CardHistory
WHERE [Status]!='')
) AS sub
WHERE Score>=17;



--- B där det ska vara W, eller W där det ska vara B?
SELECT *
FROM (
SELECT CardID, [Status], LAG([Status], 2, 'X') OVER (ORDER BY CardID) AS LagStatus
FROM dbo.CardHistory
) AS sub
WHERE [Status]='B' AND LagStatus='' OR
[Status]='W' AND LagStatus!='';




--- Stämmer dbo.DealerStatus med dbo.CardHistory?
SELECT ISNULL(h.[Status], ds.[Status]) AS [Status],
h.Deals AS [Deals, dbo.CardHistory],
ds.Deals AS [Deals, dbo.DealerStatus],
CAST(100.0*h.Deals/NULLIF(SUM(h.Deals) OVER (PARTITION BY (SELECT NULL)), 0) AS numeric(10, 3)) AS [Distr, %],
ISNULL(h.Deals, 0)-ISNULL(ds.Deals, 0) AS [(diff)]
FROM (
SELECT [Status], COUNT(*) AS Deals
FROM dbo.CardHistory
WHERE [Status]!=''
GROUP BY [Status]
) AS h
FULL JOIN dbo.DealerStatus AS ds ON h.[Status]=ds.[Status]
--WHERE ISNULL(h.Deals, 0)!=ISNULL(ds.Deals, 0)
ORDER BY h.Deals DESC;
Jonas
New Member
New Member
Posts: 13


--
10 Dec 2015 11:19 AM
Tack Daniel. Jag klarade ditt test script, puh!
Sergey
New Member
New Member
Posts: 16


--
10 Dec 2015 01:24 PM
Tack till arrangörerna för årets spännande tävling. Det är kul att få vinna när så många vassa utveklare är med!

Jag har delat upp lösningen i tre steg:
1. läsa in kort i inmemory variabeltabell
2. processa den för att hitta kort med status i en native compilerade procedur
3. uppdatera CardHistory tabellen med dessa statusar
Andra steget måste ske serielt men resten kunde gå att köra parallellt tänkte jag. Efter ett antal misslyckade försök att få till ”native” parallelism i dessa bitar satsade jag på Service Broker ramverket för att skapa egen parallellism. Tack Mikael Eriksson för vågad och inspirerande lösning förra året! Jag har dragit en växel till på detta och skapade flera köer med separata aktiveringar. Totalt 16 köer som processar varsin 1/16 del av alla kort.

När första SB tråd startar så triggar den nästa tråd och sedan laddar sin del av kort i inmemory variabel tabell. Nästa tråd laddar nästa 1/16 del av kort i inmemory variabeltabel och väntar på signal från föregående tråd att börja andra steget. När första tråden är klar med andra steget (arbetsvärden sparas i en hjälptabell [ProcessCardFlowResult]) och innan den fortsätter med steg tre så skickar den signal till nästa tråd att starta andra steget. Efter tredje steget är klar avslutar varje tråd sin SB dialog. Och så funkar det som fallande domino tills alla trådar är klara. En förgrundprocedur triggar första tråden och väntar sedan på avslutningsmeddelande från alla trådar, därefter uppdateras DealerStatus från [ProcessCardFlowResult] tabellen.

Sista optimeringen handlade om att minimera störningar mellan parallella trådar. För detta delar jag upp alla kort på en storlek som är jämnt delbar på 506 (antal rader på en data sida) och hintar mina frågor med PAGLOCK.

Setup: http://pastebin.com/vXD2imT7
Main: EXEC dbo.MainRun

Så skapade jag min testdatabas: http://pastebin.com/bB2mwdZd

//Sergey
Ulf Sjunnesson
New Member
New Member
Posts: 1


--
10 Dec 2015 01:57 PM
Snyggt!

Grattis till vinsten Sergey!
stefan gustafsson
New Member
New Member
Posts: 29


--
11 Dec 2015 10:43 AM
Attans! Tvåa igen!

Grattis Sergey!

Min lösning var väldigt lik den vinnande i varje fall i stora drag.

Jag skapade en pipeline där hela kortmassan delades upp i ett antal block och varje block processades i tre steg:
1: Ladda data från CardHistory till en memory table
2: Processa datan med en native procedure
3: Uppdatera CardHistory med resultatet.

Min lösning finns här: http://pastebin.com/gAU6Xj1K
Längst ner i mitt lösningsscript finns ett enkelt diagram i textform som visar hur de olika blocken i pipelinen processas.

Sergeys lösning fungerar bättre med ett mindre antal kort och tekniken med en kö per worker-tråd är elegant! Det skall jag använda mig av i fortsättningen.
Själv använde jag ungefär samma teknik som förra årets vinnare, en enda kö och så skickar man ett antal meddelanden till samma kö och låter kömonitorn skapa flera workers genom att vänta några sekunder.

Min lösning är dock något snabbare för större mängder kort (25000 shuffels) enligt mina egna tester. Anledningen är förmodligen i huvudsak att min lösning använder fler än 16 block för större mängder kort.

Sergeys lösning verkar dock vara något stabilare. Min lösning varierar ganska ordentligt från körning till körning.

Sergey är helt klart en värdig vinnare!

Daniels teknik med char(8000) för att få färre rader i inmemory-tabellen kan säkert också vara intressant att lägga på minnet för framtida tävlingar.

Tack för en som vanligt intressant tävling!
Jag är imponerad av hur ni alltid lyckas komma på uppgifter som kan lösas på många olika sätt med helt olika egenskaper.
/SG
You are not authorized to post a reply.
Page 2 of 3 << < 123 > >>