Partitioned View

SQL Server 2008 wprowadza widoki partycjonowane. Służą one do optymalizacji zapytań na bardzo dużej ilości danych. Rozważmy scenariusz w którym mamy 12 tabel, przechowujących archiwalne informację o sprzedaży np. JanuarySales, FebruarySales, MarchSales itd. Dane przechowywane w tych tabelach różnią się tylko czasem (dana tabela przechowuje wyłącznie informacje z określonego miesiąca). Aby móc skorzystać z widoku partycjonowanego należy użyć ograniczenia CHECK na kolumnie, będącej kryterium podziału:

CREATE TABLE JanuarySales
(
    OrderID      INT,
    Month      INT
    CHECK (Month = 1),
    CONSTRAINT OrderIDMonth PRIMARY KEY(OrderID, Month)
)

Budowanie partycjonowanego widoku niczym nie różni się od klasycznego widoku:

CREATE VIEW Sales
AS
SELECT * FROM JanuarySales
UNION ALL
SELECT * FROM FebruarySales
UNION ALL
SELECT * FROM MarchSales
...--i tak dla reszty miesiecy

Widok Sales jest teraz partycjonowany. Co to oznacza? Załóżmy, że teraz wykonujemy poniższe zapytanie:

SELECT * from Sales WHERE Month in (1,2) and Price>1

SQL Server zoptymalizuje zapytanie i będziemy przeszukiwać tak naprawdę wyłącznie tabele JanuarySales i FebruarySales.  Zamiast przeszukiwać 12 tabel, będziemy szukać danych tylko w 2 tabelach.

Narzędzia Azure – zaczynamy.

Na MSDN pojawi się cykl artykułów związanych z platformą Azure. Przeznaczony jest on dla początkujących (przynajmniej pierwsze artykuły). Jeśli nie miałeś jeszcze styczności z Azure to jest doskonały moment aby przekonać się jakie możliwości dostarcza nam ta platforma. Zapraszam do pierwszego artykułu z tej serii- Azure Tools czyli podstawowe narzędzia niezbędne do pracy z Azure: http://msdn.microsoft.com/pl-pl/library/gg455965

PowerShell i SQL Server

Powershell to interpreter poleceń oferujący dużo większe możliwości niż popularny CMD. Jedną z wyróżniających cech PowerShell’a jest logika obiektowa. Wszystkie produkty serwerowe Microsoft’u mogą być obsługiwane z poziomu PowerShell’a można zatem pisać np. skrypty konfiguracyjne. SQL Server nie jest oczywiście wyjątkiem i również wspiera PS. SQL Server PowerShell wykorzystuje hierarchię obiektów – tabela należy do schematu, schemat do bazy itd. W ramach SQL Server PS dostępne są trzy foldery:

  1. SQLSERVER:\SQL – folder zawiera obiekty, bazy, tabele itp.
  2. SQLSERVER:\SqlPolicy.
  3. SQLSERVER:\SQLRegistration.

Aby rozpocząć pracę z konsolą PS należy np. kliknąć na bazie danych w SQL Management Studio i z menu kontekstowego wybrać Start PowerShell:

image

W ramach konsoli mamy do dyspozycji m.in. standardowe komendy:

  1. Get-Location – zwraca nazwę aktualnej lokacji (aliasy: pwd, gl).
  2. Set-Location – zmienia aktualną lokalizację (aliasy: cd,sl).
  3. Get-ChildItem – zwraca listę obiektów w danej lokalizacji (np. listę tabel). Aliasy: dir, ls).
  4. Move-Item – przenosi węzeł (aliasy: mi, move, mov).
  5. Rename-Item – zmienia nazwę węzła (aliasy:rn).
  6. Remove-Item – usuwa aktualny węzeł (aliasy:ri, del, rd).

Wykonując polecenie Get-ChildItem (dir) na węźle bazy zostaną zwrócone obiekty, które przechowuje baza – czyli Tables, Triggers, Stored Procedures itp:

image

 

Wejdźmy więc do węzłą “Tables”:

>Set-Location Tables

Następnie wylistujmy wszystkie obiekty w Tables:

>Get-ChildItem

image

Jak widać cała baza danych ma strukturę hierarchiczną i możną ją utożsamiać ze zbiorem katalogów na dysku.

Generic Test

W Visual Studio można stworzyć tzw. Generic Test. Co to takiego? Jest to po prostu wrapper na narzędzie dostarczone przez kogoś innego. Powiedzmy, że do przetestowania jakiegoś modułu wykorzystujemy narzędzie stworzone przez zewnętrzna firmę. Za pomocą Generic Test możemy podpiąć zewnętrzne narzędzie i wykorzystywać zalety testów VS (np. raportowanie). W konfiguracji Generic Test określamy m.in. ścieżkę do zewnętrznego narzędzia, przyjmowane argumenty oraz opcjonalne parametry (zmienne środowiskowe, dodatkowe pliki). Jeśli wywołany plik exe zwróci 0 wtedy test zostanie uznany przez VS jako zaliczony.

image

Atrybut kolumny ROWGUIDCOL

Część osób wykorzystuje jako klucze główne typ uniqueidentifier zamiast standardowych liczb całkowitych. Ma to związek m.in. z rozproszonymi bazami danych oraz ich scalaniem. Jeśli wykorzystujemy uniqueidentifier jako klucz główny warto ustawić atrybut ROWGUIDCOL na TRUE. Powoduje to, że wartości kluczy będą automatycznie wypełniane unikalnymi wartościami. ROWGUIDCOL działa w podobny sposób co IDENTITY dla liczb całkowitych. Warto jednak podkreślić, że ROWGUIDCOL nie gwarantuje unikalności – jeśli wstawimy dwie takie same wartości w pole, SQL Server nie zwróci błędu.

Smoke Test i Sanity Test

Nie będę tłumaczył na polski powyższych nazw bo nie mam pojęcia jak to oficjalnie zostało nazwane. W każdym razie, cechą wspólną powyższych testów jest szybkość i pobieżność – stanowią one wstęp do prawdziwego, gruntowanego testowania. Poniżej kilka najważniejszych cech opisujących smoke test:

  1. Zwykle zautomatyzowany – np. w formie testu jednostkowego.
  2. Testuje każdą warstwę systemu pobieżnie.
  3. Sprawdza czy najważniejsze fragmenty systemu działają, nie wgłębiając się w logikę biznesową.
  4. Ma charakter horyzontalny a nie wertykalny – weryfikuje wszystkie aspekty pobieżnie.
  5. Smoke test wywodzi się z testowania sprzętu – podłączamy nowe urządzenie i sprawdzamy czy nie… wybuchnie. Jeśli pojawi się dym wtedy wiemy, że coś poszło nie tak:). Nazwa określa po prostu szybkie testy które w jakimś stopniu potrafią sprawdzić czy aplikacja działa.

Z kolei Sanity Test charakteryzuje się:

  1. Stanowi podgrupę testów regresyjnych wykonywanych po naprawieniu pewnego błędu – weryfikuje czy po zmianie kodu, aplikacja nadal działa w sposób przewidywalny.
  2. Zwykle niezautomatyzowany (chodź z tym można dyskutować…).
  3. Należy do tej samej grupy testów co smoke test – weryfikacja pobieżna.
  4. Testowanie wertykalne a nie horyzontalne.

Powyższe testy to raczej kwestia nazewnictwa. Wykonywane są wciąż w formie testów jednostkowych lub manualnych. Każdy chyba po kilku zmianach “przeklikowuje” aplikację czyli wykonuje tak naprawdę manualny smoke test:).

Kopiowanie dużej ilości danych z jednego źródła do drugiego

Jak sprawnie i szybko przekopiować dane z tabeli do tabeli? Można wykorzystać klasę SqlBulkCopy, która jest znacznie lepszym rozwiązaniem niż użycie klasycznego SqlCommand z poleceniem INSERT. Załóżmy, że chcemy przekopiować dane z tabeli o nazwie “Adresy” do tabeli “Adresy_Archiwum”:

using (SqlConnection sourceConnection =
         new SqlConnection(connectionString))
{
  sourceConnection.Open();
    
  SqlCommand commandSourceData = new SqlCommand(
      "SELECT * FROM Adresy", sourceConnection);
  SqlDataReader reader =
      commandSourceData.ExecuteReader();
  
  using (SqlConnection destinationConnection =
             new SqlConnection(connectionString))
  {
      destinationConnection.Open();
  
      using (SqlBulkCopy bulkCopy =
                 new SqlBulkCopy(destinationConnection))
      {
          bulkCopy.DestinationTableName =
              "dbo.Adresy_Archiwum";
          
         bulkCopy.WriteToServer(reader);
        
      }
  }
}

Jak widać należy stworzyć dwa osobne połączenia SqlConnection.

Testowanie prywatnych metod i pól – publicize.exe

W testach jednostkowych czasami warto testować również prywatne metody. Wynika to z zasady atomowości. Prywatne metody z reguły zawierają atomowe operacje, wykorzystywane potem w metodach publicznych. Jednym ze sposóbów jest użycie mechanizmu refleksji. W tym poście zajmiemy jednak się narzędziem publicize.exe, służącym do zmieniania modyfikatorów prywatnych na publiczne. Załóżmy, że mamy taką klasę:

class Klasa
{
   private int _PrywatnePoleA;
   private int _PrywatnePoleB;
   private event EventHandler Zdarzenie;
}

Uruchamiamy Visual Studio Command Prompt i wpisujemy:

publicize.exe NazwaBiblioteki.dll

Program wygeneruje nową bibliotekę, w której prywatne pola (_PrywatnePoleA, _PrywatnePoleB) będą dostępne jako publiczne. Wygenerowana biblioteka (NazwaBiblioteki_Accessor.dll) nazywana jest “Private Accessor”. Po podłączeniu do projektu, możemy przekonać się, że prywatne pola zostały zastąpione publicznymi:

ClassLibrary1.Klasa_Accessor klasa;
klasa._PrywatnePoleA = 3;
klasa._PrywatnePoleB = 6;