Archive for the ‘Teaser’ Category

SQL fejtörő 11.

Wednesday, March 11th, 2015

Feladat: van egy trading accountunk, ezen hol nyerünk, hol vesztünk. Az account nem mehet 0 alá, de ha nagyobb a veszteségünk mint az account értéke, a broker behajtja rajtunk a veszteséget, vissza kell pótolni a pénzt. A feladat számla mozgásainak összegzése.

Az elvárt kimenet az SQL tartalomban látható.

USE tempdb;

IF OBJECT_ID(N'dbo.Trades', N'U') IS NOT NULL DROP TABLE dbo.Trades;

CREATE TABLE dbo.Trades
(
  tradeId INT NOT NULL PRIMARY KEY,
  amount  INT NOT NULL
);

INSERT INTO dbo.Trades(tradeId, amount)
   values (1,12),(2,-25),(3,40),(4,10),(5,-23),(6,-32),(7,14),(8,-23),(9,12),(10,-20),(11,13),(12,-90);
GO

--Elvárt kimenet:
--tradeId	amount	accountValue	moneyBack
--1	12	12	0
--2	-25	0	13
--3	40	40	0
--4	10	50	0
--5	-23	27	0
--6	-32	0	5
--7	14	14	0
--8	-23	0	9
--9	12	12	0
--10	-20	0	8
--11	13	13	0
--12	-90	0	77

A megfejtéseket szokás szerint kommentben várom, amelyeket 4 nap múlva engedek ki.

A Test Driven Development tanfolyam következő felvonása április 20-án lesz, jövő hét szerdáig még 25% kedvezménnyel lehet jelentkezni!

SQL fejtörő 10.

Monday, March 9th, 2015

Feladat: az alábbi lekérdezés nagyon lassan fut le, nálam a költsége SQL Server 2014 alatt 1145 sec. Hozzá kellene írni a selecthez valamit, amitől a költsége leesik sokkal kisebbre.

USE TempDB
GO

CREATE TABLE Table1 (A CHAR(5) NOT NULL)
CREATE TABLE Table2 (B VARCHAR(1000) NOT NULL)
GO

INSERT Table1
SELECT LEFT(AddressLine1, 5) AS A
FROM AdventureWorks2014.Person.Address

INSERT Table2
SELECT AddressLine1 AS B
FROM AdventureWorks2014.Person.Address
GO

SELECT *
FROM Table1
INNER JOIN Table2 ON
    Table2.B LIKE Table1.A + '%'

A megfejtéseket szokás szerint kommentben várom, amelyeket 4 nap múlva engedek ki.

A Test Driven Development tanfolyam következő felvonása április 20-án lesz, jövő hét szerdáig még 25% kedvezménnyel lehet jelentkezni!

SQL fejtörő 8. – megoldás

Monday, March 9th, 2015

Kérdés.

Az IO műveleteket csak SQL Server 2014-től lehet hathatósan kordában tartani, a Resource Governor képes tetszőleges számú IO művelet/sec-re bekorlátozni a zabolátlan processzt.

Korábbi verziókban értünk el sikereket azzal, hogy a MAXDOP-ot vettük kisebbre egy lekérdezéshez. Igaz, ez nem az IO-t fogja vissza, de egy szálon csak nem tud annyi IO-t kihasítani magának egy folyamat, mint többön. Ez csak a ha ló nincs jó a szamár is megoldás.

Valójában persze a legjobb megoldás megpróbálni optimalizálni a lékérdezést/módosítást, nem futtatni olyan sűrűn (cache-elés), éjszakára időzíteni ha nem sürgős, esetleg Always On-os vagy sima replikációs másodpéldányon futtatni.

.NET fejtörő 6. – megoldás

Friday, February 27th, 2015

Feladat.

Nincs mit írnom a megoldásról, Varga Tamás kolléga (ezek köszönet érte) annyira részletesen, alaposan kielemezte a témát a kommentek között, hogy ennél én csak kevesebbet tudnék írni, övé a szó, olvassátok.

.NET fejtörő 5. – megoldás

Sunday, February 22nd, 2015

A fejtörő.

Molnár Csaba olyan teljesen megválaszolta a kérdést (köszönet érte), hogy a kommentjét egy az egyben bepasztázom:

C#-ban az idexer egy indexelt property, aminek alapértelmezetten Item a neve. Ezért fordítási hibát kapunk ennél a kódnál, hogy már van definíció az Item-re.
Ezt kétféle módon tudjuk elkerülni:
1. Az Item property-t átnevezzük valami másra.
2. Használjuk az indexeren az IndexerNameAttribute-ot, amivel megadhatjuk, hogy milyen néven jöjjön létre az indexer (ne Item néven).

Én személy szerint nem erőltetném a névütközést, inkább választanék más nevet.

Ami pluszként érdekes a példában (nekem nem volt magától értetődő), hogy lehet használni a params módosítót indexer esetén is.

SQL fejtörő 7. – megoldás

Sunday, February 22nd, 2015

Kérdés: meg tudom-e nézni egy hosszan futó SQL DML lekérdezésnél, hogy a mögötte futó operátorok (join, index seek, stb.) hány százaléknál járnak?

SQL Server 2014-től igen!

Nézzük a következő (buta) lekérdezést:

SET STATISTICS PROFILE ON;
GO
--Next, run your query in this session
select * from [dbo].[Nums] n1 cross join dbo.Nums n2;

Ez egy lassú, sok soros cross join, csak demó célra. A vizsgálandó lekérdezést olyan sessionben kell futtatni, amiben a STATISTICS PROFILE be van kapcsolva.

Így néz ki a végrehajtási terve:

CrossJoinPlan

A terv fontos a következőkhöz, azért raktam ide. És most jön a lényeg: sys.dm_exec_query_profiles. Ő mutatja meg, belül mi zajlik:

SELECT  
   node_id,physical_operator_name, SUM(row_count) row_count, SUM(estimate_row_count) AS estimate_row_count, 
   CAST(SUM(row_count)*100 AS float) / SUM(estimate_row_count) PercentComplete
FROM sys.dm_exec_query_profiles 
--WHERE session_id=54
GROUP BY node_id,physical_operator_name
ORDER BY node_id;

A végrehajtás kezdetén így néz ki a kimenete (ha valaki tud tippet adni, hogy lehet ezt SyntaxHighlighterrel jól formázni megköszönöm):

node_id	physical_operator_name	row_count	estimate_row_count	PercentComplete
0	Parallelism		1320422		4294967295		0.030743470422631
1	Nested Loops		1323284		4294967296		0.0308101065456867
2	Clustered Index Scan	15		100000			0.015
3	Table Spool		1323284		1410065408		0.0938455757082157
4	Clustered Index Scan	400000		400000			100

Egy perccel később:

node_id	physical_operator_name	row_count	estimate_row_count	PercentComplete
0	Parallelism	15917761	4294967295	0.370614254002137
1	Nested Loops	15920504	4294967296	0.370678119361401
2	Clustered Index Scan	161	100000	0.161
3	Table Spool	15920504	1410065408	1.12906138322911
4	Clustered Index Scan	400000	400000	100

Mit jelen ez? A terv alapján van két clustered index scanünk. Az egyik felolvasta a táblában található 400000 sort, azzal ő végzett is. Aztán a cilusos join elkezdi hozzávenni a tábla sorait, minden sorhoz 400000-et. Az egész eredménye belekerül a Table Spoolba, majd csurog ki a Parallelism operátoron keresztül (ami Gather Stream műveletet hajt végre, azaz összegyűjti a több szál által összerakott sorokat egy streambe, mivel párhuzamos a terv).

Lássuk be, marha érdekes látni, hogy áll belül egy nagyobb DML művelet, nem?

.NET fejtörő 4. – megoldás

Saturday, February 14th, 2015

Kérdés: miért nem jó, ha az ASP.NET Machine Key-emet Random.NextBytes()-szal generálom?

A Machine Key-t alapban viewstate validálásra használja az ASP.NET. HMAC algoritmussal csinál egy hasht, amihez a Machine Key-t mint kulcsot is felhasználja. Ez a kevésbé problémás dolog. Ami sokkal veszettebb, hogy amikor beléptetünk valakit az ASP.NET forms security-vel, akkor a beléptetett felhasználót azonosító adatot ezzel a Machine Key-jel titkosítják. Ha valaki megismeri ezt a kulcsot, akkor tud generálni kamu kukit, amibe azt a user id-t ír be, amit csak akar. Azaz meg tud személyesíteni másokat. Ebből aztán lesz spoofing, vagy akár elevation of privilege. Magyarul senki nem szeretné, ha bárki más beléphetne a nevében egy védett website-on. Például az internetes bankjába.

Szóval, talán most már érthető, a Machine Key-t nem szeretnénk, ha bárki megszerezné vagy kitalálná. Megszerezni csak a site feltörésével lehet, és admin jogokkal, tegyük fel ez nem történt meg. Ha azonban a véletlen sorozat generátorunk kiszámítható, akkor más is ugyanazzal az algoritmussal tud generálni egy olyan kulcsot, amit én is generáltam. És már jönnek is be más nevében.

A .NET Random pszeudo-random generátor, azonos seed-del mindig ugyanaz a sorozat jön ki belőle. Azt mondjátok de én ravasz vagyok, és beadom a DateTime.Now.Ticket neki inputként, az úgysem tudja a támadó. Nem tudja, de pörgetni ő is tudja ezt a számot addig, amíg ki nem találja a megfelelő seedet.

Mi a megoldás? Olyan random generátor kell, ami teljesen kiszámíthatatlan. Pl. a termikus zaj digitalizálva tökéletesen jó erre a célra. Ha ilyen modul nincs a gépben, akkor a Windows megpróbál valami nagyon randommal kijönni, például összerakva olyan vad perf counter értékeket, mint a proci ventilátor sebessége és egyebek.

A lényeg, hogy ha cripto szinten random érték kell, akkor az RNGCryptoServiceProvider típust kell használni erre a célra.

Egyébként meg IIS 7.5-től machine key-t tud generálni az IIS Manager GUI is. :)

SQL fejtörő 9.

Friday, February 13th, 2015

Van egy táblánk, amiben számokat tárolunk. A számok nem teljesen folytonosak, az összefüggő részeket kell azonosítani.

use tempdb;

IF OBJECT_ID('dbo.Tabla', 'U') IS NOT NULL DROP TABLE dbo.Tabla;
GO
CREATE TABLE dbo.Tabla
(
	szam INT NOT NULL CONSTRAINT PK_Tabla PRIMARY KEY
);
INSERT INTO dbo.Tabla(szam)
VALUES(12),(13),(111),(112),(113),(237),(238),(340),(350),(351);
GO

select * from Tabla;

-- Ezt szeretnénk kinyerni, az összefüggő tartományokat
--tartomanyeleje	tartomanyvege
--12				13
--111				113
--237				238
--340				340
--350				351

A megfejtéseket szokás szerint kommentben várom, amelyeket 2 nap múlva engedek ki.

.NET fejtörő 3. – megoldás

Tuesday, February 10th, 2015

Íme a kiírás.

Álljon itt újra a kód is:

struct Counter
{
    int counter;
    public override string ToString()
    {
        return counter++.ToString(CultureInfo.InvariantCulture);
    }
}

[TestMethod]
public void Teaser3()
{
    var sb = new StringBuilder();
            
    var sz = new Counter();
            
    sb.Append(sz);
    Object p = sz;
    Object o = p;
    sb.Append(sz);
    sb.Append(o);
    sb.Append(p);
    sb.Append(o);

    Assert.AreEqual("01234", sb.ToString());
}

Először lemaradt a feladatból a Counter struktúra, anélkül nem volt sok értelme a feladatnak, ezért az első pár választ nyilván félre mehetett.
A feladatban az a trükk, hogy nem class, hanem struktúra a Counter típus. A StringBuilderben a végén 00012 lesz. Miért?

Az sz egy a veremben tárolt struktúra. Az sb.Append() (ebben az esetben) objektumot vár paraméterül (ami reference type), amin meghívja a ToString() metódust, és ennek kimenetét rakja bele az építendő stringbe. Azonban az sz egy struktúra, value type, így azt a CLR-nek fel kell másolnia a heapre. Ezt hívják boxingnak. Ezen pont után a ToString() már a másolaton hívódik meg, az eredeti sz counter mezeje érintetlen marad.
Mivel postfix ++ operátort használunk, a kifejezés kimenete a növelés előtti érték lesz, azaz 0. Ez az első számunk.
Az Object p = sz explicit felboxolja sz-t a heapre. Az Object o = p pusztán egy másik referencia lesz ugyanerre az értékre.
Ezek után sb.Append(sz) újra boxol és kiírja a 0-t, mint a korábbi esetben. Ez a 2. számunk. Sokan szerintem itt már 1-et vártak, ami így is lenne, ha a Counter classként lenne definiálva.
Az sb.Append(o) az eddig még érintetlen felboxolt példányon hívódik meg. Mivel megint csak postfix ++ van, ez is 0 lesz. Ez a 3. 0.
Az sb.Append(p) ugyanezen példányra mutat, így végre ő már megnövelheti a számlálót 2-re, és visszaadhatja az 1-et. Ez a 4. számunk, ami végre 1.
Az sb.Append(o) pedig újra végigjátssza a növelést a más ismerős példánnyal, így jön ki belőle 2.

Ha a típusunk class lett volna, akkor jött volna ki belőle 01234.

A példának látszólag nincs jelentősége, a generikus típusok óta valóban kevesebb baj van a struktúrákkal. De még .NET 1.0-ban láttam olyat, amikor HashTable[“valami”]++ után a x = HashTable[“valami”] változatlan értéket adott vissza, meglepve a kollégákat. Most már talán érthető, miért.

SQL fejtörő 8.

Tuesday, February 10th, 2015

SQL Serveren dolgozva van egy agresszív lekérdezés, amely szétzúzza a diszket, így a többi lekérdezés nem kap elég időt, kiéhezteti őket. Mit tudok tenni?

.NET fejtörő 3. hiánypótlás

Friday, February 6th, 2015

Elnézést azoktól, akik filóztak a 3. .NET feladaton, elfelejtettem belerakni a Counter típust, anélkül semmi értelme a feladatnak. Így már érthető, miért nem jött rá megoldás. :)

Most akkor neki lehet esni még egyszer.

SQL fejtörő 7.

Friday, February 6th, 2015

Meg tudom-e nézni egy hosszan futó SQL DML lekérdezésnél, hogy a mögötte futó operátorok (join, index seek, stb.) hány százaléknál járnak?

.NET fejtörő 4.

Thursday, February 5th, 2015

Ez most egy elméleti kérdés lesz. Van egy web farmom. Az ASP.NET Machine Key-emet legeneráltam a Random.NextBytes() segítségével, és beraktam minden gép machine.configjába. Mi a probléma a megoldásommal?

.NET fejtörő 3 – nincs megoldás?

Thursday, February 5th, 2015

Itt volt ez a fejtörő, de nem jött rá megoldás. Ennyire nem nehéz. Valaki?

.NET fejtörő 3.

Thursday, January 22nd, 2015

Update: bocs, a Counter osztály lemaradt, így nem volt értelme a feladatnak.

Piros vagy zöld lesz a teszt kimenete? Válaszokat indoklással kommentben várom. A hozzászólások moderálva vannak, hogy 2 napot tudjam késleltetni a válaszokat, így mindenkinek lesz ideje gondolkodni. Jó filózást!


struct Counter
{
    int counter;
    public override string ToString()
    {
        return counter++.ToString(CultureInfo.InvariantCulture);
    }
}

[TestMethod]
public void Teaser3()
{
    var sb = new StringBuilder();
            
    var sz = new Counter();
            
    sb.Append(sz);
    Object p = sz;
    Object o = p;
    sb.Append(sz);
    sb.Append(o);
    sb.Append(p);
    sb.Append(o);

    Assert.AreEqual("01234", sb.ToString());
}

A Test Driven Development tanfolyam következő felvonása 2015. február kilencedikén lesz, szeretettel várlak.

.NET fejtörő 2.

Tuesday, January 20th, 2015

Piros vagy zöld lesz a teszt kimenete? Válaszokat indoklással kommentben várom. A hozzászólások moderálva vannak, hogy 2 napot tudjam késleltetni a válaszokat, így mindenkinek lesz ideje gondolkodni. Jó filózást!

[TestMethod]
public void Teaser2()
{
    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < 10; i++)
    {
        sb.Append(i + ' ');
    }

    Assert.AreEqual("1 2 3 4 5 6 7 8 9", sb.ToString());
}

A Test Driven Development tanfolyam következő felvonása február kilencedikén lesz, szeretettel várlak.

SQL fejtörő 6.

Friday, January 16th, 2015

Ez a fejtörő most sokkal nehezebb lesz. Adottak számlák és számla tételek. A számla tételek különböző ÁFA kategóriákba tartoznak. Elveszett viszont, hogy melyik tétel melyik ÁFA kategóriába tartozik. Csak összesítve tudjuk, hogy egy adott számlán mennyi volt az egyes ÁFA tételű termékek össz értéke. A feladat visszaállítani minden egyes tétel ÁFA kulcsát. Az adatok úgy vannak összerakva, hogy a feladat egyértelműen megoldható legyen.

Bemeneti adatok:

Számlák:

ID	Szamlaszam	OsszAr	Ado
1	Szamla1	500.00	Afa27
2	Szamla1	300.00	Afa16
3	Szamla2	4000.00	Afa38

Számla tételek:

ID	Szamlaszam	Ar
1	Szamla1	20.00
2	Szamla1	111.00
3	Szamla1	250.00
4	Szamla1	20.00
5	Szamla1	15.00
6	Szamla1	189.00
7	Szamla1	100.00
8	Szamla1	95.00
9	Szamla2	1000.00
10	Szamla2	3000.00

Elvárt kimenet, Adó, számlaszám és id szerint van rendezve:

id	Szamlaszam	Ar	Ado
2	Szamla1	111.00	Afa16
6	Szamla1	189.00	Afa16
1	Szamla1	20.00	Afa27
3	Szamla1	250.00	Afa27
4	Szamla1	20.00	Afa27
5	Szamla1	15.00	Afa27
7	Szamla1	100.00	Afa27
8	Szamla1	95.00	Afa27
9	Szamla2	1000.00	Afa38
10	Szamla2	3000.00	Afa38

Többféle megoldás is adható, mindegyik legalább 15 soros.

use tempdb;

IF OBJECT_ID('Szamlatetel','U') IS NOT NULL BEGIN
  DROP TABLE Szamlatetel
END 
GO

CREATE TABLE Szamlatetel(
	[ID] [INT] IDENTITY(1,1) NOT NULL,
	Szamlaszam [VARCHAR](20) NOT NULL,
	Ar [DECIMAL](18,2) NOT NULL	
)
GO

INSERT INTO Szamlatetel(Szamlaszam,Ar) 
SELECT 'Szamla1', 20 UNION ALL
SELECT 'Szamla1', 111 UNION ALL
SELECT 'Szamla1', 250 UNION ALL
SELECT 'Szamla1', 20  UNION ALL
SELECT 'Szamla1', 15  UNION ALL
SELECT 'Szamla1', 189 UNION ALL
SELECT 'Szamla1', 100 UNION ALL
SELECT 'Szamla1', 95 UNION ALL
SELECT 'Szamla2', 1000 UNION ALL
SELECT 'Szamla2', 3000
go

IF OBJECT_ID('Szamlafej','U') IS NOT NULL BEGIN
  DROP TABLE Szamlafej
END 
GO

CREATE TABLE Szamlafej(
	[ID] [INT] IDENTITY(1,1) NOT NULL,
	Szamlaszam [VARCHAR](20) NOT NULL,
	OsszAr [DECIMAL](18,2) NOT NULL DEFAULT(0),
	[Ado] [VARCHAR](5) NOT NULL
)
GO

INSERT INTO Szamlafej(Szamlaszam, OsszAr, Ado) 
SELECT 'Szamla1', 500, 'Afa27' UNION ALL
SELECT 'Szamla1', 300, 'Afa16' UNION ALL
SELECT 'Szamla2', 4000,  'Afa38'

SELECT * FROM Szamlafej;
GO
SELECT * FROM Szamlatetel order by id;
GO

A megfejtéseket szokás szerint kommentben várom, amelyeket ezúttal a feladat nehézsége miatt 5 nap múlva engedek ki.

A Test Driven Development tanfolyam következő felvonása február kilencedikén lesz, szeretettel várom az érdeklődőket.

.NET fejtörő 1.

Thursday, January 15th, 2015

Piros vagy zöld lesz a teszt kimenete? Válaszokat indoklással kommentben várom. A hozzászólások moderálva vannak, hogy 2 napot tudjam késleltetni a válaszokat, így mindenkinek lesz ideje gondolkodni. Jó filózást!

[TestMethod]
public void Teaser1()
{
    try
    {
        var a = Math.PI;
        var b = 0;
        var c = a / b;
    }
    catch (DivideByZeroException exception)
    {
        Assert.Fail("A kutya fáját");
    }
}

A Test Driven Development tanfolyam következő felvonása 2015. február kilencedikén lesz, szeretettel várlak.

SQL fejtörő 5.

Tuesday, January 13th, 2015

Egyszerű lekérdezéses feladat:

use tempdb;

create table Ember
(
	Nev nvarchar(50) not null,
	Telefon nvarchar(50) not null
);
go

insert Ember(Nev, Telefon)
values 
('Gizi', '22222222'),
('Gizi', '00000000'),
('Géza', '11111111'),
('Mari', '33333333');
go

--Ide jön a te query-d:

--A lekérdezés elvárt kimenetében minden név egyszer szerepel, és mindhez egy telefonszám, az, amelyik abc sorrendben az első:
--Géza	11111111
--Gizi	00000000
--Mari	33333333

drop table Ember;

A megfejtéseket szokás szerint kommentben várom, amelyeket 2 nap múlva engedek ki.

A Test Driven Development tanfolyam következő felvonása február kilencedikén lesz, szeretettel várom az érdeklődőket.

SQL fejtörő 4.

Friday, January 9th, 2015

Ez most könnyű lesz. Tegyük fel ügyetlen voltam, és lefuttattam az alábbi kódot. Nincs is megnyitott kapcsolatom a szerverre. Mit tehetek? Reinstall?

CREATE TRIGGER AFrancbaTrigger
ON ALL SERVER
FOR LOGON
AS
BEGIN
    ROLLBACK;
END;

A megfejtéseket szokás szerint kommentben várom, amelyeket 2 nap múlva engedek ki.

A Test Driven Development tanfolyam következő felvonása február kilencedikén lesz, szeretettel várlak.