poniedziałek, 17 czerwca 2013

Optymalizacja zapytań skorelowanych

Na początek, krótkie wyjaśnienie czym jest zapytanie skorelowane, a prawidłowo ujmując - podzapytanie skorelowane. Z Wikipedii możemy odczytać: "zapytanie skorelowane, to takie zapytanie, które w podzapytaniu korzysta w klauzurze WHERE z danych z zapytania zewnętrznego. Zapytanie skorelowane jest wykonywane dla każdego wiersza przetwarzanego przez zapytanie zewnętrzne."

Druga część definicji daje nam obraz tego, iż stosowanie podzapytań skorelowanych dla dużych zbiorów danych jest nieefektowne i prowadzi do obniżenia wydajności całego systemu.
Co więc należy zrobić? Unikać zapytań skorelowanych a w przypadku już istniejących - przerabiać je w miarę możliwości na zapytania nieskorelowane.

Przykład na żywym organizmie:

Przykładowa baza danych - AdventureWorks2012 - jest ogólnie dostępna do pobrania ze stron Codeplex.
Treść zapytania które będziemy analizowali:
Z tabeli produktów wybrać te, których cena jest większa od średniej ceny produktów tego samego rozmiaru:

SELECT p.ProductID, p.Name, p.StandardCost
FROM Production.Product p
WHERE p.StandardCost > (SELECT AVG(StandardCost) FROM Production.Product WHERE Size = p.Size)


Takie zapytanie dla każdego wiersza zapytania zewnętrznego, policzy najpierw średnią cenę produktu o danym rozmiarze a następnie ją porówna z zewnętrznym wierszem.

Powyższe zapytanie można przepisać do następującej postaci:

SELECT p.ProductID, p.Name, p.StandardCost
FROM Production.Product p JOIN 
 (SELECT size, AVG(StandardCost) avgStandardCostPerSize
 FROM Production.Product
 GROUP BY Size) p2 
ON p2.Size = p.Size 
WHERE p.StandardCost > p2.avgStandardCostPerSize


Zapytanie wydłużyło się, jednak jest rozbite na dwa etapy. Najpierw zostaną zgrupowane produkty o tym samym rozmiarze i policzona ich średnia cena, a następnie z tym wynikiem zostanie połączona tabela produktów.

Nie każde zapytanie da się optymalizować. Niektóre będą wymagały większej ilości czasu poświęconego na ich analizę. Zysk jednak zostanie odczuty wraz z kolejnymi tysiącami wierszy w tabelach.

środa, 12 czerwca 2013

WCF REST Routing

Jeżeli ktoś miał okazję pisać w ASP.NET MVC, z pewnością docenia możliwości jakie daje routing. Dzięki jego zastosowaniu upraszcza się ścieżka prowadząca do żądanych zasobów.
WCF od wersji .NET 4.0 także pozwala na zastosowanie routingu i zastąpienie standardowego Service.svc/zasób ścieżką bardziej przyjazną.

Aby możliwe było użycie routingu w WCF, podobnie jak w przypadku MVC należy dodać plik Global.asax i w nim skonfigurować na starcie nasz serwis:

Code:
        protected void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes();
        }

        private static void RegisterRoutes()
        {
            var webServiceHostFactory = new WebServiceHostFactory();
            RouteTable.Routes.Add(new ServiceRoute("MyService", webServiceHostFactory, typeof(Service1)));
        }


To wszystko co jest wymagane aby routing działał. Teraz w przeglądarce możemy przetestować czy rozwiązanie działa poprawnie.

Standardowe wywołanie:


Wywołanie z zastosowaniem routingu:



Jak widać obie wersje działają. Mechanizm bardzo użyteczny i bardzo dobrze się stało, że został zaimplementowany w WCF REST.

Kod źródłowy przykłądu do pobrania:  http://sdrv.ms/11plYts

wtorek, 11 czerwca 2013

WCF Rest - automatyczne formatowanie odpowidzi

WCF 4.0 wprowadza bardzo fajny dodatek pozwalający na automatyczne formatowanie odpowiedzi w zależności od wartości nagłówka Accept. Już nie trzeba ustawiać na metodzie czy ma zwracać JSON czy też XML. Wystarczy przesłać odpowiednią wartość nagłówka Accep np. text/xml dla XML lub application/json dla JSON.

Aby możliwe były formatowanie w zależności od nagłówka Accept, należy ustawić atrybut automaticFormatSelectionEnabled na wartość "true":

Code:
      <endpointBehaviors>
        <behavior name="web">
          <webHttp automaticFormatSelectionEnabled="true"/>
        </behavior>
      </endpointBehaviors>


Po tym zabiegu możemy przetestować rozwiązanie np. za pomocą Fiddlera:



Odpowiedź:



Jeżeli zmienimy teraz na text/xml:



Otrzymamy odpowiedź:



Tak więc bez dodatkowej pracy możemy formatować odpowiedź do dogodnej dla nas postaci.


Kod źródłowy przykładu: http://sdrv.ms/14okftO

poniedziałek, 10 czerwca 2013

Zwracanie błędów w WCF REST

Tworząc usługi na platformie WCF, aby rzucić wyjątek stosowaliśmy FaultException<T>.
REST jako protokół HTTP rządzi się innymi prawami i w jego przypadku wygodniej jest stosować WebFaultException<T>.

Przykład:

Code:
        public string GetData(int value)
        {
            if (value < 10)
            {
                return string.Format("You entered: {0}", value);
            }

            throw new WebFaultException<string>("Value is too large", HttpStatusCode.ExpectationFailed);
        }

Kiedy spróbujemy wprowadzić wartość większą od 10 zostanie rzucony wyjątek, który następnie możemy odczytać w naszej aplikacji. Dodatkowo mamy dostępny kod błędu, co ułatwia identyfikowanie wyjątków.

Ekran z Fiddler-a:





Cały kod przykładu do pobrania: http://sdrv.ms/18XTjC6