Jeśli masz zapytanie lub procedurę składowaną, która wymaga dostrojenia wydajności, jakie są niektóre z pierwszych rzeczy, które należy wypróbować?
Jeśli masz zapytanie lub procedurę składowaną, która wymaga dostrojenia wydajności, jakie są niektóre z pierwszych rzeczy, które należy wypróbować?
Odpowiedzi:
Oto poręczna lista rzeczy, które zawsze daję komuś, kto pyta mnie o optymalizację.
Używamy głównie Sybase, ale większość porad ma zastosowanie we wszystkich przypadkach.
Na przykład SQL Server jest dostarczany z wieloma bitami monitorowania / dostrajania wydajności, ale jeśli nie masz czegoś takiego (a może nawet jeśli masz), rozważę następujące ...
99% problemów , które widziałem, jest spowodowanych umieszczeniem zbyt wielu tabel w złączeniu . Rozwiązaniem tego problemu jest wykonanie połowy złączenia (z niektórymi tabelami) i buforowanie wyników w tabeli tymczasowej. Następnie wykonaj resztę zapytania, dołączając do tej tabeli tymczasowej.
#temp
tabele mogą działać znacznie lepiej niż @table
zmienne o dużych wolumenach (tysiące wierszy).Trochę poza tematem, ale jeśli masz kontrolę nad tymi kwestiami ...
Wysoki poziom i duży wpływ.
CREATE INDEX
Upewnij się, że dostępne są indeksy dla Twoich WHERE
i JOIN
klauzul. To znacznie przyspieszy dostęp do danych.
Jeśli Twoje środowisko to hurtownia danych lub hurtownia danych, indeksy powinny obfitować w prawie wszystkie możliwe zapytania.
W środowisku transakcyjnym liczba indeksów powinna być niższa, a ich definicje bardziej strategiczne, aby utrzymanie indeksów nie obciążało zasobów. (Utrzymanie indeksu ma miejsce, gdy liście indeksu muszą zostać zmienione, aby odzwierciedlić zmianę w tabeli bazowej, tak jak w przypadku operacji INSERT, UPDATE,
i DELETE
).
Zwróć także uwagę na kolejność pól w indeksie - im bardziej selektywne (większa liczność) pole, tym wcześniej powinno się pojawić w indeksie. Załóżmy na przykład, że szukasz używanych samochodów:
SELECT i.make, i.model, i.price
FROM dbo.inventory i
WHERE i.color = 'red'
AND i.price BETWEEN 15000 AND 18000
Cena ma generalnie wyższą moc. Może być dostępnych tylko kilkadziesiąt kolorów, ale prawdopodobnie tysiące różnych cen wywoławczych.
Spośród tych opcji indeksu idx01
zapewnia szybszą ścieżkę do spełnienia zapytania:
CREATE INDEX idx01 ON dbo.inventory (price, color)
CREATE INDEX idx02 ON dbo.inventory (color, price)
Dzieje się tak, ponieważ mniej samochodów spełnia wymagania cenowe niż wybór koloru, co daje silnikowi zapytań znacznie mniej danych do analizy.
Wiadomo, że mam dwa bardzo podobne indeksy różniące się tylko kolejnością pól przyspieszających zapytania (imię, nazwisko) w jednym i (nazwisko, imię) w drugim.
Sztuczka, której ostatnio się nauczyłem, polega na tym, że SQL Server może aktualizować zmienne lokalne, a także pola, w instrukcji aktualizacji.
UPDATE table
SET @variable = column = @variable + otherColumn
Lub bardziej czytelna wersja:
UPDATE table
SET
@variable = @variable + otherColumn,
column = @variable
Użyłem tego do zastąpienia skomplikowanych kursorów / złączeń podczas wykonywania obliczeń rekurencyjnych, a także znacznie zyskałem na wydajności.
Oto szczegóły i przykładowy kod, który wprowadził fantastyczną poprawę wydajności: http://geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal. aspx
Zakładając tutaj MySQL, użyj EXPLAIN, aby dowiedzieć się, co się dzieje z zapytaniem, upewnij się, że indeksy są używane tak wydajnie, jak to możliwe, i spróbuj wyeliminować sortowanie plików. Wysokowydajny MySQL: optymalizacja, kopie zapasowe, replikacja i nie tylko to świetna książka na ten temat, podobnie jak MySQL Performance Blog .
@Terrapin Istnieje kilka innych różnic między isnull i coalesce, o których warto wspomnieć (poza zgodnością z ANSI, która jest dla mnie duża).
Generalnie zacznę od złączeń - wyrzucę każde z nich z zapytania pojedynczo i ponownie uruchomię zapytanie, aby dowiedzieć się, czy istnieje konkretne złączenie, z którym mam problem.
Na wszystkich moich tabelach tymczasowych lubię dodawać unikalne ograniczenia (w stosownych przypadkach), aby tworzyć indeksy i klucze podstawowe (prawie zawsze).
declare @temp table(
RowID int not null identity(1,1) primary key,
SomeUniqueColumn varchar(25) not null,
SomeNotUniqueColumn varchar(50) null,
unique(SomeUniqueColumn)
)
Przyzwyczaiłem się zawsze używać zmiennych wiążących. Możliwe, że zmienne powiązania nie pomogą, jeśli RDBMS nie buforuje instrukcji SQL. Ale jeśli nie używasz zmiennych wiążących, RDBMS nie ma szansy na ponowne wykorzystanie planów wykonywania zapytań i przeanalizowanych instrukcji SQL. Oszczędności mogą być ogromne: http://www.akadia.com/services/ora_bind_variables.html . Pracuję głównie z Oracle, ale Microsoft SQL Server działa prawie w ten sam sposób.
Z mojego doświadczenia wynika, że jeśli nie wiesz, czy używasz zmiennych wiążących, prawdopodobnie tak nie jest. Jeśli Twój język aplikacji ich nie obsługuje, znajdź taki, który to obsługuje. Czasami można naprawić zapytanie A, używając zmiennych wiązania dla zapytania B.
Następnie rozmawiam z naszym DBA, aby dowiedzieć się, co powoduje największy ból w RDBMS. Zauważ, że nie powinieneś pytać „Dlaczego to zapytanie jest wolne?” To tak, jakby poprosić lekarza, aby usunął wyrostek robaczkowy. Pewnie, że Twoje zapytanie może być problemem, ale jest równie prawdopodobne, że coś innego jest nie tak. Jako programiści myślimy raczej w kategoriach linii kodu. Jeśli linia jest wolna, napraw ją. Ale RDBMS to naprawdę skomplikowany system i twoje powolne zapytanie może być symptomem znacznie większego problemu.
Zbyt wiele wskazówek dotyczących tuningu SQL to idole kultu cargo. W większości przypadków problem jest niezwiązany lub minimalnie związany z używaną składnią, więc zwykle najlepiej jest używać możliwie najczystszej składni. Następnie możesz zacząć szukać sposobów dostrojenia bazy danych (nie zapytania). Popraw składnię tylko wtedy, gdy to się nie powiedzie.
Jak w przypadku każdego dostrajania wydajności, zawsze zbieraj znaczące statystyki. Nie używaj zegara ściennego, chyba że dostosowujesz ustawienia użytkownika. Zamiast tego spójrz na takie rzeczy, jak czas procesora, pobrane wiersze i bloki odczytane z dysku. Zbyt często ludzie optymalizują się pod kątem niewłaściwych rzeczy.
Uruchamianie zapytania za pomocą WITH (NoLock) jest w moim przypadku standardową operacją. Każdy przyłapany na wykonywaniu zapytań na dziesiątkach gigabajtów tabel bez tego jest usuwany i rozstrzeliwany.
Jeśli to możliwe, konwertuj zapytania NOT IN na LEFT OUTER JOINS. Na przykład, jeśli chcesz znaleźć wszystkie wiersze w tabeli Tabela1, które nie są używane przez klucz obcy w tabeli2, możesz to zrobić:
SELECT *
FROM Table1
WHERE Table1.ID NOT IN (
SELECT Table1ID
FROM Table2)
Ale dzięki temu uzyskasz znacznie lepszą wydajność:
SELECT Table1.*
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.Table1ID
WHERE Table2.ID is null
Niekoniecznie jest to sztuczka wydajnościowa SQL jako taka, ale zdecydowanie związana:
Dobrym pomysłem byłoby użycie memcached tam, gdzie to możliwe, ponieważ byłoby znacznie szybsze pobieranie wstępnie skompilowanych danych bezpośrednio z pamięci, niż pobieranie ich z bazy danych. Istnieje również odmiana MySQL z wbudowanym memcached (strona trzecia).
Upewnij się, że długość indeksu jest jak najmniejsza. Pozwala to DB odczytać więcej kluczy na raz z systemu plików, przyspieszając w ten sposób łączenie. Zakładam, że działa to ze wszystkimi bazami danych, ale wiem, że jest to konkretna rekomendacja dla MySQL.
Zwracam uwagę na:
SET NOCOUNT ON
Zwykle jest to pierwsza linia w moich procedurach składowanych, chyba że faktycznie muszę użyć @@ROWCOUNT
.
W SQL Server użyj dyrektywy nolock. Pozwala na wykonanie polecenia select bez czekania - zwykle na zakończenie innych transakcji.
SELECT * FROM Orders (nolock) where UserName = 'momma'
Usuń wywołania funkcji w Sprocs, gdzie wiele wierszy będzie wywoływać funkcję.
Mój kolega użył wywołań funkcji (na przykład pobierając lastlogindate z identyfikatora użytkownika), aby zwrócić bardzo szerokie zestawy rekordów.
Mając zadanie optymalizacji, zastąpiłem wywołania funkcji w sproc kodem funkcji: zmniejszyłem czas działania wielu sproców z> 20 sekund do <1.
Lubię używać
isnull(SomeColThatMayBeNull, '')
Nad
coalesce(SomeColThatMayBeNull, '')
Kiedy nie potrzebuję wsparcia dla wielu argumentów, które daje Ci połączenie.
http://blog.falafel.com/2006/04/05/SQLServerArcanaISNULLVsCOALESCE.aspx
Nie poprzedzaj nazw procedur składowanych przedrostkiem „sp_”, ponieważ wszystkie procedury systemowe zaczynają się od „sp_”, a SQL Server będzie musiał dokładniej szukać procedury, gdy zostanie wywołana.
set transaction isolation level read uncommitted
Zapobiega martwym blokadom, w których integralność transakcyjna nie jest absolutnie konieczna (co zwykle jest prawdą)
Zawsze najpierw przechodzę do programu SQL Profiler (jeśli jest to procedura składowana z wieloma poziomami zagnieżdżania) lub planera wykonywania zapytań (jeśli jest to kilka instrukcji SQL bez zagnieżdżenia). W 90% przypadków można natychmiast znaleźć problem za pomocą jednego z tych dwóch narzędzi.