2011-06-21 1 views
7

Mam kwerendę w następujący sposób;Powolne działanie SQL

SELECT COUNT(Id) FROM Table 

Tabela zawiera 33 miliony rekordów - zawiera klucz podstawowy na Id i brak innych indeksów.

Zapytanie trwa 30 sekund.

Rzeczywisty plan wykonania pokazuje, że używa on sklasyfikowanego indeksu.

Przeanalizowaliśmy tabelę i stwierdziliśmy, że nie jest ona pofragmentowana przy użyciu pierwszego zapytania wyświetlanego w tym łączu: http://sqlserverpedia.com/wiki/Index_Maintenance.

Wszelkie sugestie, dlaczego to zapytanie jest takie powolne i jak to naprawić.

definicji tabeli:

CREATE TABLE [dbo].[DbConversation](
[ConversationID] [int] IDENTITY(1,1) NOT NULL, 
[ConversationGroupID] [int] NOT NULL, 
[InsideIP] [uniqueidentifier] NOT NULL, 
[OutsideIP] [uniqueidentifier] NOT NULL, 
[ServerPort] [int] NOT NULL, 
[BytesOutbound] [bigint] NOT NULL, 
[BytesInbound] [bigint] NOT NULL, 
[ServerOutside] [bit] NOT NULL, 
[LastFlowTime] [datetime] NOT NULL, 
[LastClientPort] [int] NOT NULL, 
[Protocol] [tinyint] NOT NULL, 
[TypeOfService] [tinyint] NOT NULL, 
    CONSTRAINT [PK_Conversation_1] PRIMARY KEY CLUSTERED 
(
[ConversationID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

Jedno zauważyłem jest baza danych jest ustawiona rosnąć w kawałki 1 MB.

Jest to system na żywo, więc ograniczyliśmy to, w co możemy się bawić - jakieś pomysły?

UPDATE:

OK - mamy lepszą wydajność w rzeczywistym zapytania zainteresowania poprzez dodanie nowych wskaźników non-skupione na odpowiednich kolumnach tak, że nie jest to już poważny problem.

SELECT COUNT jest wciąż powolny - wypróbowany z podpowiedziami NOLOCK - bez różnicy.

Wszyscy myślimy, że ma to coś wspólnego z ustawieniem Autogrowth na 1Mb zamiast większej liczby, ale zaskoczyło nas, że ma taki efekt. Czy możliwa jest fragmentacja MDF na dysku?

+1

Pytanie 1: czy naprawdę potrzebujesz dokładnej liczby? A może tylko szacunek? –

+0

Ani - jest to tylko zapytanie, które uruchomiliśmy po zaobserwowaniu powolnego działania na czymś innym. Zaskoczyło nas to, że było tak wolno. Spróbuję zaktualizować statystyki, ale zostaną ustawione na automatyczne odliczanie. – BonyT

+0

Nie możesz po prostu użyć stałej? Chodzi mi o to, jak wpływa na ciebie różnica między tym, że ma 33 miliony "lub faktycznie mająca 33.212.293 zapisy? – bevacqua

Odpowiedz

5

Czy jest to tabela często odczytywana/wstawiana/aktualizowana? Czy aktywność aktualizacji/wstawiania jest współbieżna z wybranym?

Zgaduję, że opóźnienie wynika z rywalizacji.

Jestem w stanie uruchomić licznik na 189-milionowych wierszach w ciągu 17 sekund na moim serwerze dev, ale nic innego nie trafia w ten stół.

Jeżeli nie jesteś zbyt zaniepokojeni niezgody lub absolutną dokładnością można zrobić:

exec sp_spaceused 'MyTableName' które dadzą liczbę oparciu o meta-danych.

Jeśli chcesz bardziej dokładnej liczby, ale nie koniecznie obchodzi czy ona odzwierciedlać współbieżne DELETE lub INSERT aktywność można zrobić swoje aktualne zapytanie o NOLOCK podpowiedź:

SELECT COUNT(id) FROM MyTable WITH (NOLOCK) który nie dostanie blokad na poziomie wierszy dla Twoje zapytanie i powinno działać szybciej.

+0

Niezbyt zajęta baza danych - twierdzenie nie jest problemem (oświadczenie prawie zawsze zajmuje dokładnie ten sam czas, aby odpowiedzieć na 30-ty i użycie wskazówki NOLOCK nie robi żadnej różnicy.) – BonyT

+0

@BonyT - W takim razie masz inne problemy. Jak szeroki jest ten stół? Nie odnosi się to bezpośrednio do 'COUNT', ale ma wpływ na liczbę stron, które SQL musi pobrać, aby uzyskać liczbę, która może mieć znaczenie przy wyższych wolumenach. Jakie masz inne problemy z perf? – JNK

+0

Zaakceptowany, chociaż może nigdy nie wiedzieć, jaki problem był/jest tutaj, jak na kogoś innego, a oni wprowadzili obejście, które rozumiem. – BonyT

1
use [DatabaseName] 

select tbl.name, dd.rows from sysindexes dd 
inner join sysobjects tbl on dd.id = tbl.id where dd.indid < 2 and tbl.xtype = 'U' 

select sum(dd.rows)from sysindexes dd 
inner join sysobjects tbl on dd.id = tbl.id where dd.indid < 2 and tbl.xtype = 'U' 

Korzystając z tych pytań można pobrać zliczania wszystkie tabele w ciągu 0-5 sekund

stosowanie klauzuli WHERE w zależności od zapotrzebowania .....

+0

Strona referencyjna: http://planetofcoders.blogspot.com/2011/06/how-to-count-all-rows-in-particular.html –

+1

uważnie przeczytaj post, jego troską nie jest "wybierz liczbę" (id) 'raczej powolna wydajność zapytania – Rahul

2

Myśli:

  • Stosować SELECT COUNT(*) który jest poprawny dla "ile wierszy" (zgodnie z ANSI SQL). Nawet jeśli ID jest PK, a zatem nie jest zerowalne, SQL Server zliczy ID. Nie wiersze.

  • Jeśli możesz żyć z przybliżoną liczbą, użyj sys.dm_db_partition_stats. Zobacz moją odpowiedź tutaj: Fastest way to count exact number of rows in a very large table?

  • Jeśli można żyć z brudnymi czyta używać WITH (NOLOCK)

+0

To naprawdę nie ma znaczenia, ponieważ optymalizator efektywnie używa tego samego planu, niezależnie od tego, co umieszczasz w nawiasach. Niektóre osoby są wybredne w użyciu "*". Cokolwiek to jest nieistotne w tej kwestii. – BonyT

+0

@BonyT: Jeśli uważasz, że jest "wybredny", sugeruję, abyś zweryfikował, czy jestem świadomy [różnic] (http://stackoverflow.com/questions/1221559/count-vs-count1/1221649#1221649), ale liczę (col) może nie dawać tego samego planu co count (*). Stąd moja sugestia – gbn

+0

Tak, mamy - zaczęliśmy od * :) – BonyT

0

inny pomysł: Kiedy pliki rosną z częściami 1MB może zostać rozdrobnioną w systemie plików. Nie widzisz tego przez SQL, widzisz to za pomocą narzędzia do defragmentacji dysku.