Archive for the ‘SQL Server 2005’ Category

SQLCLR deplyment hiba

Wednesday, January 27th, 2010

Error: Incorrect syntax near valami.
Akkor jön elő, ha az SQLCLR assemblyt és benne a függvényeket akarja az VS deployolni. Több oka lehet, most az volt, hogy egy .NET oldalon double-t visszaadó függvény véletlenül így lett deklarálva:


[SqlFunction(..., TableDefinition = "Datum datetime, Szazalek double")]

Mi a hiba benne? SQL Serverben nincs double, csak real és float. Ráadásul a C# float az az SQL real és a C# double az SQL Server float (kb.). :)

Az előbbi helyesen:


[SqlFunction(..., TableDefinition = "Datum datetime, Szazalek float")]

Miért kellett SQLCLR függvényt írni? A futó aggregálások (én legalábbis nem tudok jobbat kurzor nélkül) o(n2)-es algoritmusok, ezt CLR-ben könnyen meg lehet írni o(n)-re. Pl:


using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public class UserDefinedFunctions
{
    internal class Result
    {
        public long RowId;
        public double CumDollarGain;
        public double TopDollarGain;
        public double DollarDrawDown;
    }

    //Input table: create table #trades(RowId long, DollarGain money, other columns possible)
    [SqlFunction(FillRowMethodName = "FillRow", DataAccess = DataAccessKind.Read,
        TableDefinition = "RowId bigint, CumDollarGain float, TopDollarGain float, DollarDrawDown float")]
    public static IEnumerable Cumul()
    {
        using (var conn = new SqlConnection("Context connection=true"))
        {
            using (var cmd = new SqlCommand("select RowID, DollarGain from #trades", conn))
            {
                var res = new List<Result>();
                conn.Open();
                double cumulPrice = 0, topPrice = 0, drawDawn = 0;

                using (SqlDataReader r = cmd.ExecuteReader())
                {
                    int idCol = r.GetOrdinal("RowID");
                    int gainCol = r.GetOrdinal("DollarGain");

                    while (r.Read())
                    {
                        var price = r.GetDouble(gainCol);

                        cumulPrice += price;
                        topPrice = Math.Max(price, topPrice);

                        drawDawn += price;
                        drawDawn = Math.Min(drawDawn, 0);

                        res.Add(new Result
                                    {
                                        RowId = r.GetInt64(idCol),
                                        CumDollarGain = cumulPrice,
                                        TopDollarGain = topPrice,
                                        DollarDrawDown = drawDawn
                                    });
                    }
                    return res;
                }
            }
        }
    }
    public static void FillRow(object obj,
    out long id,
    out double cumDollarGain,
    out double topDollarGain,
    out double dollarDrawDown)
    {
        var r = (Result)obj;
        id = r.RowId;
        cumDollarGain = r.CumDollarGain;
        topDollarGain = r.TopDollarGain;
        dollarDrawDown = r.DollarDrawDown;
    }
};

Sajnos nem lehet átpasszolni a megnyitott SqlDataReadert a két metódus között, ezért kénytelen az ember letárolni az eredményhalmazt. Persze pár ezer sornál ez nem gond.

Random orderby Linq és EF használatával

Monday, October 12th, 2009

Az SQL Serveren szokásos orderby newid() szerveroldali megoldást csak linq to SQL esetén tudjuk kihasználni, szerveroldali függvénnyel. Az EF-ben az ilyesmi nem megy:


... orderby Guid.NewID() ...

Ez az EF verzió még nem tudja lefordítani szerveroldali kifejezéssé az orderby kifejezését.
Viszont a random rendezést át lehet nyomni kliensoldalra, ha a lekérdezést “materializáluk” (AsEnumerable) előbb:


Random rnd = new Random();
(from s in ATSEntities.Instance.Symbol
select s).AsEnumerable().OrderBy(o => rnd.Next()));

Nem guidot használtam, hanem Randomot, az kisebb költségű, és az én célomra nem baj, ha csak pszeudo-random a sorrend.

Deadlock bulk load során

Tuesday, August 4th, 2009

Párhuzamos bulk betöltések esetén deadlockolhatnak egymással a másoló szálak, főleg, ha vannak FK-ek a táblákon.

Sokféle megoldás adható a problémára.
1. Átmeneti táblába töltünk, amin nincsenek indexek és fk-k.
2. Lekezeljük a deadlockot, és ismétlünk.
3. tablock-kal töltünk be, ezzel azonban súlyosan visszavethetjük a párhuzamosságot.
Ezt ki lehet kényszeríteni központilag is:
EXEC sp_tableoption ‘Tick’, ‘table lock on bulk load’, ‘1′

Nekem ez jó volt, mert nálam az adatforrás volt lassú 1 szálon, ezért kellett 40, az SQL betöltések sorosítva is elég gyorsak, és nincs deadlock.

Reporting Services 2008 for Custom Aggregation

Friday, July 24th, 2009

A RS 2008-ban ez más, mint 2005-ben, itt leírják miért és hogyan.

Ha valakit tud tippet arra, hogyan lehet _saját_ _running_ aggregate-eket írni, az érdekelne. Nem sikerült megbízható módon megcsinálnom, működik, de nem mindig.

Histogramgenerálás SQL-ből

Monday, July 20th, 2009

SQL magazinból.
Fenn van az SQL Magazine 2000-2004 között itt az msdnen, jó cikkek vannak benne.

Scatter riportok a Reporting Servicesben

Wednesday, July 15th, 2009

A legtöbb riport item az RS-ben intuitív, na, ez nem az. Ezzel a chart fajtával nagyon jól lehet szemléltetni nagyszámú minta eloszlását, jól látszik pl. hol tömörödnek az értékek csoportokba (clusterekbe).

Nekem pl. intraday trade-ek elemzésére kiváló (példaként itt a rendszerem egyik riportja, a pötyösek a scatterek), mivel több mint ezer trade történik 2-3 évnyi adat tesztelése során, amelyek teljesítményét jól lehet vizualizálni a scatter chart segítségével valamely változó függvényében.

A chart beélesztésében ez segített.

Automatikus kurzor takarítás

Thursday, July 2nd, 2009

Na, ezt nem ismertem, pedig már 10 éve nyüvöm az SQL Servert.

Read-only filegroup, hogy ne lock-oljon az SQL Server? Nem.

Thursday, April 30th, 2009

Az egyik MCP vizsgán céloztak arra, hogy ha egy adatbázis valamely filegroupját read only-vá tesszük, akkor nem fog lockokat rárakni a szerver, hisz minek, úgyse lesznek módosító folyamatok.

Nos, ez elméletileg így lehetne, de nem így van. Ha az egész adatbázis read only, akkor viszont tényleg nem lockol, ami adhat némi teljesítmény nyereséget.

Másra azért jó:

Read-only filegroups, They provide you the following three benefits:

1. Can be compressed (using NTFS compression)
2. During recovery you don’t need to apply logs to recover a read-only file group
3. Protection of data from accidental modifications

A márciusi BI konferencia anyaga a weben

Monday, April 27th, 2009

Erről elfelejtettem írni, online minden anyag, így a screencastok is - az én részem a Reporting Services volt.

Az utóbbi időben sokat használom a Reporting Servicest a kereskedő algoritmusaim teszteredményeinek megjelenítésére, és egyre jobban szeretem.

Az Entity Frameworköt is gyúrom, na erről már vegyesebb véleményem van, de egyelőre még korai lenne világgá kürtölni, ha már jobban kiismertem, majd írok róla.

Előadásom az Architect Akadémián - SQL Server architect szemmel

Sunday, April 12th, 2009

Kicsit későn szólok, de ha valakit érdekel, még jelentkezhet, április 15-én lesz.
3×1 órában beszélek arról, hogyan lehet bevetni az SQL Serverek (2000-2008) okosságait egy új alkalmazásarchitektúra kidolgozása során. A cél nem annyira mélységi, mint szélességi bemutatása annak, mit lehet kihozni az SQL Serverből. Igyekszek olyan dolgokról is beszélni, amiről ritkán esik szó (pl. Query Notification, Service Broker), világnézet tágítás végett. Szeretném megmutatni, hogy az SQL Server nem egy egyszerű CRUD adatbázismotor, ahogy sajnos nagyon sokan használják.

Vigyázni a profilerrel!

Wednesday, March 25th, 2009

Az egyik folyó munkámban profilerrel szerettünk volna szétnézni egy szerveren, hogy lássuk, kik a lassú lekérdezések. Eddig ez minden cégnél zökkenőmentesen ment, mondjuk egy min. 5000-es read filter mellett szépen jött a lista. Esetünkben azonban a profiler bekapcsolása után gyakorlatilag elérhetetlenné vált az sql server, de olyannyira, hogy még be se tudtunk rá lépni, újra kellett indítani. Először azzal ideologizáltuk meg a dolgot, hogy lassú volt a kapcsolat a profilert futtató gép és az sql server között, de ugyanígy lefagyott akkor is, ha egy azonos LAN-on levő gépről futott a kliens.
Esetünkben nem egy sima terhelési minta kellett, hanem kellettek az XML Planek is, gondolom ez feküdte meg a gyomrát, ezek előállítása.
Kevésbé megterhelő módja a valódi planek kinyerésének a management view-k használata. A következő lekérdezés visszaadja a hangoláshoz számomra fontos infókat:


SELECT top 500
OBJECT_NAME(st.objectid) object_name, 

SUBSTRING(ST.text, (QS.statement_start_offset/2) + 1,
((CASE statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE QS.statement_end_offset END
- QS.statement_start_offset)/2) + 1) statement_text,

qs.last_execution_time,
qs.execution_count, 

qs.total_worker_time,
qs.total_worker_time / qs.execution_count agv_worker_time,
qs.last_worker_time,

qs.total_logical_reads,
qs.total_logical_reads / qs.execution_count avg_logical_reads,
qs.last_logical_reads,
qp.query_plan as query_plan_text,
xp.query_plan
--into tempdb.dbo.Plans
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) as st
CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle,
qs.statement_start_offset, qs.statement_end_offset) AS qp
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) xp
order by total_worker_time desc

Az utolsó oszlop az xml plan, csak rá kell kattintani, és máris látszik grafikusan a terv. Szenzációsan kényelmes.

Supporting SQL Server 2008: The system_health session

Wednesday, March 18th, 2009

Az extended event-ökre épülő dolog, ez, amelyet problémák esetén érdemes megnézni a szokásos logok mellett:


SELECT CAST (xest.target_data AS XML)
FROM sys.dm_xe_session_targets xest
JOIN sys.dm_xe_sessions xes ON
xes.address = xest.event_session_address
WHERE xes.name = 'system_health';

A háttérben fut egy extended event session, ami a gázosabb helyzetekben logol. Igaz, csak korlátozott méretekben és memóriában, de lehet benne hasznos infó.
Ezekről van benne infó:
* The sql_text and session_id for any sessions that encounter an error with severity >=20
* the sql_text and session_id for any sessions that encounter a “memory” type of error such as 17803, 701, etc (we added this because not all memory errors are severity >=20)
* A record of any “non-yielding” problems (you have sometimes seen these in the ERRORLOG as Msg 17883)
* Any deadlocks that are detected
* The callstack, sql_text, and session_id for any sessions who have waited on latches (or other interesting resources) for > 15 seconds
* The callstack, sql_text, and session_id for any sessions who have waited on locks for > 30 seconds
* The callstack, sql_text, and session_id for any session that have waited for an extended period of time for “external” waits or “pre-emptive waits”.

Jó tudni még, hogy az sql log könyvtárában vannak trc fájlok is, amelyek meg a már 2005 óta létező, háttérben futó default trace nyomait rögzíti. Ebben is lehetnek értékes morzsák hibakereséshez.

SQL Server: Lock Pages In memory on 64 bit platform

Tuesday, March 17th, 2009

Yes, we do recommend to turn on Lock pages in memory so that OS doesn’t page SQL Server out. On 64 bit you only need to grant the right “Lock Pages in Memory” to the SQL account for SQL Server to utilize this feature.

Kapcsolódik még.

Ha ez a hiba előjön főleg nézzetek utána:
“A significant part of sql server process memory has been paged out. This may result in performance degradation”

De már megyek is vissza a munkához, mert igencsak beindult az élet, egyszerre 6 cég számára futnak munkáim, és most adok ajánlatot a jövő héten egy újabb, várhatóan elég nagy volumenű feladatra. Igaza van Marcellnak, válság más cégnél van, nálunk miért lenne? Ezzel nem akarom nagyképűen lebecsülni sok ember nagyon is valós gondját kölcsönproblémák és egyáltalán a megélhetés miatt, csak azt akarom megerősíteni, hogy attól, hogy a gazdasági folyamatok nem a helyükön vannak, attól még megy az élet, folyik az építkezés sok helyen. Van egy ismerősöm, aki kereskedelemből él, és mondta, hogy a ő cégére is igen nehéz idők járnak, nem tudja, nyáron is létezni fog-e még a cége.
Nehéz kikapcsolni a sok negatív hangot, ami az utóbbi hónapokban a csapból is folyik, nem tesz jót az ember motivációjának. De jön a tavaszi szél, remélem ez sok mindenben új vizet áraszt. Az amerikai tőzsde már mocorog (de még messze nincs vége a medveszezonnak), akkor talán 1 év múlva már nálunk is fog. És utána talán a magyar gazdaság is megindul.

Mikor építhetünk a sorok sorrendjére SQL Serverben?

Thursday, March 12th, 2009

Nappal DP tanfolyamot tartottam, éjszaka meg adatbázist optimalizálok egy ügyfelemnek, így most csak egy rövid, de érdekes cikket linkelek be.

Új cikkem: snapshot elszigetelési szint az SQL Server 2008-ban

Wednesday, February 25th, 2009

Eléggé elfeledett téma ez az SQL Serverben, pedig önmagában ez az új szolgáltatás eladta volna az SQL 2005-öt.
Cikk.

.NET teljesítményhangolási tapasztalatok 6.

Monday, February 23rd, 2009

A Connection Poolról még pár gondolat. Jó, hogy van ez a pool, meg gyorsít is, örülünk neki, főleg webalkalmazásokban. Olyan appokban viszont, ahol állandóan futnak a dolgaink, mint egy asztali alkalmazás esetén, nem biztos, hogy érdemes mohón nyitni-zárni a kapcsolatot.
A tőzsdei kereskedési algoritmusaim backtestje során sok százezer paraméterkombinációt néz végig a gép, próbálja meghatározni a legvalószínűbb nyerési esélyűt vagy legnagyobb profit/szórással rendelkezőt (ennél jóval bonyolultabb a dolog, de ez most nem tőzsdés bejegyzés lesz).
A DAL-t úgy írtam meg ahogy webalkalmazásokban megszoktam, így minden egyes trade mentésénél nyitottam-zártam a connectiont. Profilerrel megnézve kiderült, hogy a pool ellenére is a futási idő harmada az open/close-zal ment el. Emiatt készítettem kétféle SqlHelper osztályt, az egyik állandóan nyitott kapcsolattal működik, a másik az egyéb helyekre nyit-zár mind eddig.
Összegezve, a connection pool kiváló dolog pillanatokra futó alkalmazásokhoz, mint a webalkalmazások, de nem érdemes erőltetni, ha több százezerszer kell nyitni-zárni a kapcsolatot.

SQL BI konferencia március 3-án

Thursday, February 19th, 2009

(Sose tudom, kell pont ilyenkor a dátumba?)
Előadok a fenti konfon Reporting Services témában. Mivel az SQL Server BI része (OLAP, SSIS, SSRS) sokkal kevésbé ismertek mint a relációs motor, ezért ezen az Informatika Tisztán nem a technet vagy msdn konferenciákon megszokott itt a legújabb cucc, nézd milyen kúl megközelítés lesz, hanem a kezdő lökést szeretnénk megadni az érdeklődőknek.

Érdekes nekem ez a konferencia?

Ha már régóta érzed, hogy jó lenne érteni az Analysis Serviceshez (OLAP izék), vagy nem mertél még belefogni, mert olyan megfoghatatlan katyvasznak tűnik.
Ha tudod, hogy az Integration Services a DTS utódja, ahhoz még értettél (vagy azt se tudod mi volt az), de ezt még nem nézted meg, mert azt mondták az annyira más, hogy meg se merted nézni.
Ha hallottál róla, hogy nem menő már a Crystal Reports, vagy azt se tudod hogyan kellene belefogni az első riportba (amit egyébként szó szerint 5 perc alatt össze tudsz dobni), és érdekel a Reporting Services.
Ha hallottál valami adatbányászatról, de nem tudod, hogy melyik földkéreg tartalmaz adatokat, és érdekel, hogy ez tényleg valami használható technológia, vagy csak ráérős Microsoft Research kutatók gumicicája?

Szóval alapozást ígérünk, földközelbe hozzuk ezeket a kevésbé szem előtt lévő technológiákat. Gyere, várunk.

.NET teljesítményhangolási tapasztalatok 5.

Thursday, February 12th, 2009

Szeretjük a connection poolt, de nem mindig.

Tudjuk, hogy manapság nem illik sokáig nyitva tartani az adatbázis kapcsolatot, hanem bemegyünk, kihozzuk a szükséges adatokat, majd lezárjuk a kapcsolatot. Régen (n > 10 év) ez nem volt okos dolog, mert lassú volt a belépés-kilépés. Ezért találták ki a Connection Poolt, amit OLEDB-ben még Session Poolnak hívtak. Egykutya.
Ez arról szól, hogy a kliens oldali adatelérő komponens, pl. az ADO.NET SqlClient providere (System.Data.SqlClient névtér és kölkei) újrahasznosítja a lezárt kapcsolatot. Azaz mi SqlConnection.Close-t mondunk, ő viszont a háttérben nem zárja le a kapcsolatot az adatbázis felé. Ha ezek után újra meg akarjuk nyitni egy kapcsolatot az adatbázis felé, nem hoz létre új kapcsolatot a provider, hanem visszaad egy használtat a poolból. Miért jó ez? Nyilván egy tényleges kapcsolat kiépítése igen költséges, TCP csatorna vagy Named Pipe session felépítése, autentikáció, ecetera. Ezt nagyon sokszor megússzuk, hála a poolnak. A pool 4-8 perc közötti véletlenszerű időközönként azért lezárogatja a használt kapcsolatokat, ott ne zápuljanak.
Nyilvánvaló, hogy felhasználónként egyedi poolok vannak, így egy sysadmin által eldobott kapcsolatot nem adja oda nekem, lópicinek a provider, ez csúnya luk lenne.
Lehet azért így is aljaskodni az új bérlőkkel. Mi van, ha becsatlakozok, kiadok egy use másik adatbázist, majd röhögve lezárom a kapcsolatot? És ha egy-ket set opciót átírok, pl. SET LANGUAGE urdi? Mit lát a következő hívó, aki megkapja a használt kapcsolatot? Hát amit beállítottunk az előző lépésben. Azért ez durván hangzik, ugye? Szerencsére a helyzet az, hogy alapban tiszta környezetet kapunk, köszönhetően annak, hogy a provider pool manager-e végrehajt egy sp_reset_connection hívást mielőtt visszaadná nekünk a használt kapcsolatot. Hogy ez pontosan mit csinál, azt egyszer már leírtam, tessék megnézni a listát.
Azaz bár nem kell minden egyes kéréshez új kapcsolatot megnyitni, azért egy sp hívás csak történik pluszban a háttérben. SQL Profilerben látszik, hogy ez nagyon gyors, de azért ez mégis csak egy hálózati körülfordulás.
És most jön a trükk. Ha teljesen biztosak vagyunk benne, hogy nem tolunk ki a következő hívóval aki megkapja a használt kapcsolatunkat, akkor kikapcsolhatjuk a takarítást. A connection stringbe ezt kell beírni:


Connection Reset=false;

Nézzük meg az alábbi kódot:


SqlConnection conn = new SqlConnection("data source=.;initial catalog=ATS;Integrated security=true;");
SqlCommand cmd = new SqlCommand("sp_who", conn);
cmd.CommandType = CommandType.StoredProcedure;

for (int i = 0; i < 3; i++)
{
    conn.Open();
    cmd.ExecuteNonQuery();
    conn.Close();
}

Az SQL Profilerben ez látszik:


EventClass	TextData	SPID
Audit Login	-- network protocol: LPC
RPC:Completed	exec sp_who 	52
Audit Logout		52
RPC:Completed	exec sp_reset_connection 	52
Audit Login	-- network protocol: LPC
RPC:Completed	exec sp_who 	52
Audit Logout		52
RPC:Completed	exec sp_reset_connection 	52
Audit Login	-- network protocol: LPC
RPC:Completed	exec sp_who 	52
Audit Logout		52

Hoppá, ez nem az, amit vártunk! Csak 1 logint az elején és 1 logoutot a végén, közben meg az sp_resetconnectiont és az sp_who-nkat. Nem működik a pooling?
De. Csibész a profiler.
“The Audit Login event class indicates that a user has successfully logged in to Microsoft SQL Server. Events in this class are fired by new connections or by connections that are reused from a connection pool.”

Ha bekapcsoljuk a profilerben az Event Subclasst, kicsit tisztul a kép:


EventClass	TextData	SPID	EventSubClass
Audit Login	-- network protocol: LPC		1 - Nonpooled
RPC:Completed	exec sp_who 	52
Audit Logout		52	2 - Pooled
RPC:Completed	exec sp_reset_connection 	52
Audit Login	-- network protocol: LPC		2 - Pooled
RPC:Completed	exec sp_who 	52
Audit Logout		52	2 - Pooled
RPC:Completed	exec sp_reset_connection 	52
Audit Login	-- network protocol: LPC		2 - Pooled
RPC:Completed	exec sp_who 	52
Audit Logout		52	1 - Nonpooled

Szóval van pooling, csak a profiler ravaszkodik. Már kivert a víz. Viszont valami ebben zavar. A pooling ugye a kliensen van. Honnan tudja a szerver egy új parancs beérkeztekor az egy új parancsnak számít a kliens részéről a még nyitott kapcsolaton, vagy csak a poolból visszakapott kapcsolaton hajtanak végre egy új parancsot?
Szerintem ő mesterségesen szintetizálja a poolos login-logoutokat, az sp_reset_connection-ök beérkeztekor veszi őket körbe login-logout párossal, a feeling kedvéért. De ez csak tipp.

Kapcsoljuk ki a connection resetet:


SqlConnection conn = new SqlConnection(
    "data source=.;initial catalog=ATS;Integrated security=true;connection reset=false;");

Mit látunk a profilerben? Semmi nem változott! .NET fw. 2.0 felett nem lehet kikapcsolni az sp_reset_connection-t! Ezért nincs már a legújabb doksiban benne ez a beállítás.

Foly. köv.

A szeptemberi SQL konferencia screencastjai elérhetőek

Tuesday, October 21st, 2008

Itt.

A screencast nem olyan pörgős és humoros mint az elő előadás volt, de nem szeretek a monitornak bohóckodni. 500 embernek már lehet. Előadás közben meglepően más helyen vagyok a tudatállapotok szivárványán, pedig nem is kokszolok. :)
Persze tartalmilag minden benne van, ami élőben ment. Jó tanulást hozzá!

Szaktanácsadó születik :-)

Tuesday, October 14th, 2008

Örömmel és nagy reményekkel közzéteszem, hogy 2009. január 1.-től független szaktanácsadóként folytatom a szakmai pályafutásom. Ennek megfelelően év végére átalakítom a website-om főlapját is, a megfelelő üzleti, kontakt, stb. információkkal kiegészítve.
A blogom változatlanul fog üzemelni, sőt, várhatóan több időm lesz rá, és jóval több témával is fogok foglalkozni (WCF, WWF, Windows Internals, DP újult erővel, stb.).

Ha .NET-alapú fejlesztéssel, tervezéssel vagy SQL Serverrel kapcsolatban tudok valakinek segíteni, januártól szabad vagyok. Az utóbbi két évben jó pár felkérést utasítottam vissza, jövőre erre már nem lesz szükség.

Részletek később, most igen sok intéznivalóm van…