27 maja 2011

Dynamiczne tworzenie i parsowanie connection stringa do SQL Servera

Jak okiełznać connection string?


Kilkukrotnie zdarzyło mi się zmierzyć z problemem tworzenia dynamicznie w kodzie connection stringa do SQL Servera.  W sytuacji gdy użytkownik wybiera lub wprowadza nazwę bazy czy instacji SQL Servera generowanie connection stringów podczas wykonania aplikacji może być pomocne.   W wersji .NET Framework 2.0 pojawiła się bardzo użyteczna klasa o nazwie SqlConnectionStringBuilder. Umożliwia ona konstruowanie connection stringa poprzez ustawianie właściwości klasy, które są zmapowane na poszczególne parametry connection stringa. Poniżej prosty przykład przygotowania połączenia do bazy master.

using System;
using System.Data.SqlClient;

namespace ConnectionStringBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            var  builder = new SqlConnectionStringBuilder();
            //use master database
            builder.InitialCatalog = "master";
            //Connect to local SQL Server instance
            builder.DataSource = @".";
            //User Windows Authentication
            builder.IntegratedSecurity = true;
            //set 30 second connection timeout.
            builder.ConnectTimeout = 30; 
            //retrieve connection string
            string connectionString = builder.ConnectionString;

            using(var connection = new SqlConnection(connectionString))
            {
                connection.Open();
            }

            Console.WriteLine(builder.ConnectionString);
        }
    }
}


20 maja 2011

Triggery DML w MS SQL Server - Cześć 2 dla zainteresowanych

Wprowadzenie


W poście 'Triggery DML w MS SQL Server' opisałem podstawowe informacje dotyczące triggerów DML implementowanych w T-SQLu. Chciałbym ten temat rozwinąć, opisując kilka zagadnień, których zrozumienie jest istotne do poprawnej implementacji DML triggerów.

Kolejność wykonywania wielu triggerów


Z bliżej nie wyjaśnionego biznesowego  powodu czasami trzeba zdefiniować kilka triggerów na danej tabeli (tylko triggery typu AFTER mogą być dodane kilka razy). Sql Server umożliwia ustalenie który z triggerów wykona się pierwszy, a który ostatni. Jeżeli mamy np. 4 triggery na danej tabeli to możemy ustawić, który trigger wykona się pierwszy, a który ostatni. Triggery wykonujące się pomiędzy pierwszym i ostatnim odpalą się w dowolnej kolejności. Należy też pamiętać, że nie można dodać danego triggera dwukrotnie do tej samej tabeli.

--use master;
--DROP DATABASE TriggerDatabase2;
GO
use master;
GO
CREATE DATABASE TriggerDatabase2;
GO
USE TriggerDatabase2;
GO

Po utworzeniu bazy uruchomimy skrytp tworzący tabelę Events. Tabelka będzie miała 4 triggery AFTER INSERT (Events_AfterInsertx).

CREATE TABLE dbo.[Events]
(
 EventName NVarchar(20) NOT NULL PRIMARY KEY,
 EventDate DateTime NOT NULL
)
GO
DECLARE @fourTriggersCount INT
SET @fourTriggersCount = 4
WHILE @fourTriggersCount > 0
BEGIN
  DECLARE @createTriggerSql VARCHAR(max)
  SET @createTriggerSql  = '
  CREATE TRIGGER Events_AfterInsert' + CAST(@fourTriggersCount AS VARCHAR) + ' 
      ON dbo.[Events]
   AFTER INSERT 
   AS 
   BEGIN
      PRINT ''Executed Events_AfterInsert' + CAST(@fourTriggersCount AS VARCHAR) + ' trigger''
   END
   '
   EXEC (@createTriggerSql)
   SET @fourTriggersCount = @fourTriggersCount - 1
END 

SELECT t.name, OBJECT_NAME(t.parent_id) TableName , te.is_first, te.is_last
  FROM sys.triggers t 
  JOIN sys.trigger_events te
    ON t.object_id = te.object_id
WHERE t.parent_id = object_id('dbo.Events')

Domyślnie kolejność wykonania triggerów nie jest ustalona. Aczkolwiek przy użyciu procedury systemowej sp_settriggerorder można ustawić który trigger będzie wykonany jako pierwszy, a który jako ostatni.

19 maja 2011

Problem z instalacją z SQL Server 2008 R2 na wirtualnej maszynie

Plik ISO SQL Server 2008 R2 zamontowany jako DVD


Podczas instalacji SQL Server 2008 R2 (instalka jako plik ISO) na maszynie wirtualnej (Windows Virtual PC, system hosta: Windows 7, system guesta Windows XP Pro SP3) dostałem następujący błąd. Jest on już zarejestrowany na Connect.

Product: SQL Server 2008 R2 Database Engine Shared -- The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2337.

17 maja 2011

Table-Valued Parameters czyli panaceum na komunikację pomiędzy aplikacją i bazą danych

TVP bez abonamentu


Table Valued Parameters (TVP - parametry tabelaryczne?) zostały wprowadzone w wersji MS SQL Server 2008. Umożliwiają one przekazywanie zmiennych tabelarycznych jako parametry procedur składowanych lub bezpośrednich zapytań. Niestety nie można przekazać TVP jako parametr funkcji.

W poprzednich wersjach SQL Servera programiści nie mogli wykorzystać tabeli do przekazania danych od klienta. Musieli albo przekazać XML który trzeba było sparsować w procedurze składownej lub przekazać tekst z delimiterami albo po prostu przesłać wiele instert'ów/update'ów.

Table Valued Parameter umożliwia bardziej ustrukturyzowane i eleganckie rozwiązanie. Programista definiuje typ danych tabelaraczny, który później wykorzysta do zdefiniowania TVP.

CREATE TYPE dbo.ShoppingBasketType AS TABLE 
( 
  ProductCode VARCHAR(10) NOT NULL PRIMARY KEY, 
  Quantity Int NOT NULL
)
GO
SELECT * FROM sys.table_types
GO

14 maja 2011

Replikacja transakcyjna - Dystrybutor, Część II

Dystrybutor - od tego należy zacząć


Dystrybutor jest kluczowym komponentem replikacji transakcyjnej. Pełni on rolę repozytorium wszystkich transakcji które zostały zreplikowane lub będą dopiero dystrybuowane do subskrybentów. Przy replikacji transakcyjnej dystrybutor może być mocno obciążony, gdyz zarówno Log Reader Agent jak i Distribution Agent komunikują się z nim intensywnie.

Wystarczy pomyśleć, że jeżeli w jednym aktykule publikacji (np. tabeli LogHistory) usuniemy 10k wierszy to Log Reader będzie musiał przesłać każde usunięcie rekordu w postaci oddzielnego polecenia (Command). Później Distribution Agent na każdym subskrybencie pobierze 10k poleceń (załóżmy, że mamy 10 subskrybentów). Zatem dystrybutor dla tego jednego polecenia DELETE będzie musiał obsłużyć (zapisać lub umożliwić odczyt 110k poleceń). Z tych i innych powodów Microsoft często zaleca skonfigurowanie dystrybutora na odzielnym serwerze, aby uniknąć problemów wydajnościowych. Poniżej przedstawiam krótki opis podstawowej konfiguracji dystrybutora przy użyciu SQL Server Management Studio (SSMS).

W pierwszym kroku w SSMS należy wybrać Replication i dalej Configure Distribution. 

13 maja 2011

Jak obliczyć medianę przy pomocy funkcji CLR User-Defined Aggregate? - Część 2 QuickSelect po liftingu

Mediana ciąg dalszy nastąpił


W pierszym poście 'Jak obliczyć medianę przy pomocy funkcji CLR User-Defined Aggregate?' został opisany sposób implmentacji funkcji agregującej (User-Defined Aggregate function) za pomocą .NET CLR w MS SQL Server 2008, a przy okazji został wykorzystany prosty algorytm do obliczania mediany.

W poszukiwaniach lepszej wydajności algortytmu obliczania mediany, zaimplementowałem algortym QuickSelect. Implementację QuickSelect'u można znależć w poście 'Algorytm selekcji Hoare'a (QuickSelect) w C# .NET'.

Kod zródłowy projektu jest dostępny tutaj.

QuickSelect po liftingu


Do obliczenia mediany należało zmodyfikować QuickSelect w taki sposób, aby obsługiwał opcję z parzystą liczbą elementów w zbiorze. Przy parzystej liczbie elementów (n) należy wyznaczyć elementy n/2 i (n/2)+1  a następnie obliczyć średnią arytmentyczną dla tych dwóch elementów. Oczywiście można uruchomić dwukrotnie QuickSelect dla k=n/2 i k=n/2 + 1, ale to oznaczałoby utratę wydajności.

Jeżeli wynaczymy n/2 element to znaczy, że w partycji po "prawej" stronie znajduje się element n/2+1. Wystarczy zatem ponowić QuickSelect'a na tej partycji  o ideksach n/2, i lastRightBoundIndex. Algorytm zamieszczam poniżej.

10 maja 2011

Algorytm selekcji Hoare'a (QuickSelect) w C# .NET

Algorytm selekcji k-tego elementu


W poprzednim poście opisałem obliczanie mediany za pomocą prostego algortymu używającego sortowania. W celu uzyskania krótszych czasów wykonania, natknąłem się na algortym selekcji Hoare'a zwany QuickSelectem. Ponieważ obliczenie mediany dla uszeregowanego zbioru n-elementowego (dla uproszczenia n jest nieparzyste), wymaga wyznaczenia k-tego element gdzie k = (n+1)/2, QuickSelect okazał się bardzo pomocny.

Poniżej podaję implementację rekurencyjną QuickSelect'a w C# , w następnym poście podam pełną wersję algorytmu obliczającego medianę.

07 maja 2011

Jak obliczyć medianę przy pomocy funkcji CLR User-Defined Aggregate?

1.Dwa słowa o medianie


Jednym z podstawowych terminów w statystyce jest mediana (median). Jej definicja jest intuicyjna i prosta do zrozumienia. Z tego powodu została wybrana do zaprezentowania koncepcji implementacji przy użyciu .NET CLR funkcji agregującej (User-Defined Aggregate function) w MS SQL Server. Mediana jest wartością środkową posortowanego szeregu danych. Jeżeli liczba n-elementów jest nieparzysta to miediana jest równa elementowi o indeksie (n+1)/2. Natomiast, jeżeli liczba elementów szeregu jest parzysta, to średnia arytmentyczna dwóch środkowych elemetów jest wartością mediany.

Przykładowe obliczenia mediany dla zbiorów Y z liczbą elementów parzystą i nieparzystą.

 Y = [1, 2, 3, 4, 8, 9, 11]
 Mediana (Y) =  4

Y =   [1, 2, 3, 4, 8, 9, 11, 12]
Mediana (Y) = (4 + 8)/2 = 6


Bardziej formalną definicję mediany można znaleść na wikipedii (polecam wersję angielską jako że autor bardziej wyczerpująco podszedł do tematu).    

Kod źrodłowy jest do ściągnięcia tutaj.

Implementacja algorytmu QuickSelect przy obliczeniu mediany została opisana w poście 'Jak obliczyć medianę przy pomocy funkcji CLR User-Defined Aggregate? - Część 2 QuickSelect po liftingu'.

2. Jak można policzyć medianę w MS SQL Server?


Medianę w SQL Server można liczyć przy użyciu skryptu w T-SQL'u , można też zaimplmenetować funkcję agregującą  (User-Defined Aggregate) przy użyciu .NET Framework. W tym arktykule skupimy się na implementacji funkcji agregującej w języku C#.

Funkcja agregująca musi być zaimplementowana jako klasa lub struktura. Klasa funkcji powinna być opatrzona atrybutem SqlUserDefinedAggregateAttribute. Atrybut ten posiada kilka istotnych właściwości, których konfiguracja jest bardzo ważna dla implementacji funkcji. 

02 maja 2011

Wersja 0.2 Weather.com .NET klienta jest już dostępna

Co nowego w wersji 0.2 biblioteki Weather.com.Client?

Nowa wersja Weather.com.Client jest już dostępna na codeplex.com. Więcej informacji o Weather.com można znaleźć w poście Prognoza pogody na dziś - Weather.com .NET klient.

Weather.com.Client API wspiera asynchroniczne wywołania funkcji.

WeatherClient client = new WeatherClient("[Partner Id here]"
, "[License Key here]");
IAsyncResult result = client.BeginGetLocation("Warsaw,Poland",null, null);
//Do some work here
// Wait until the operation completes.
result.AsyncWaitHandle.WaitOne();
List locations = _client.EndGetLocation(result);