Witam,
Na swoje potrzeby napisałem aplikację w c#, która wstawia i pobiera dane z bazy danych. Na ten moment mając 8 milionów rekordów pobranie 1600 rekordów zajmuje mi ponad minutę (zapytanie wykorzystuje EXIST i relacje z innymi tabelami). Baza danych jest uruchomiona przez Microsoft sql server a wszystko działa na VPS. Problem w tym, że ten system zarządzania bazą zabiera mi 3,5gb pamięci ram, no i działa to dość wolno. Także moje pytanie jest następujące: czy powinienem zmienić to na jakieś inne rozwiązanie? Możecie mi coś polecić?
Czy zmienić bazę danych?
- Rejestracja: dni
- Ostatnio: dni
- Rejestracja: dni
- Ostatnio: dni
Spróbować zoptymalizować bazę?
Sprawdź co jest wąskim gardłem, może brakuje jakiegoś indeksu czy coś.
1600 to bardzo mało, nawet jak masz po drodze kilka joinów.
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: U krasnoludów - pod górą
- Postów: 4714
Off topic - 3.5 gb RAM starcza na trzymanie w pamięci 8 mln rekordów jeśli rekordy maja po ok 400 bajtów. Ja sobie tak czasem te dane w RAM trzymam.
Działa to zarąbiście szybko nawet jak nie używam indeksów za bardzo tylko robię naiwny in memory full scan :-)
- Rejestracja: dni
- Ostatnio: dni
Wygląda to tak:
CREATE TABLE users (
id int INT NOT NULL IDENTITY(1,1) PRIMARY KEY,,
name VARCHAR(50),
....
);
CREATE TABLE restaurants(
id int INT NOT NULL IDENTITY(1,1) PRIMARY KEY,,
name VARCHAR(50),
profileId int,
toVisit int
....
);
CREATE TABLE occurences(
id int INT NOT NULL IDENTITY(1,1) PRIMARY KEY,,
userId int,
profileId
);
A kod wyłuskujący dane:
SELECT TOP(40) profileId FROM restaurants where NOT EXISTS (SELECT profileId FROM Occurences WHERE users.Id=" + input.Id+ " and restaurants.profileId = Occurences.profileId) and toVisit>0 and profileId>0 ORDER BY case when toVisit <= 0 then 1 else 0 end, Priority DESC, ToSecond;
W skrócie:
Mam bazę z 10 000 użytkowników i 10 000 restauracji. Chciałbym za każdym razem pobrać 40 restauracji których dany użytkownik nigdy nie odwiedził, i następnie dodać te 40 jako odwiedzone przez niego.
Bez części case trwa to prawie tyle samo. Kod wykonuję dla listy z 40 elementami input.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 60
Może to Ci pomoże : https://github.com/StackExchange/Dapper
- Rejestracja: dni
- Ostatnio: dni
SELECT TOP(40) r.profileId FROM restaurants r left join occurences o on (r.profileid=o.profileid and o.userid=@uid) where o.id is null and r.toVisit>0 and r.profileId>0 ORDER BY r.Priority DESC, r.ToSecond;
do parametru @uid przekaż warość input.id, dodaj też odpowiednie indeksy na tabele i powinno śmigać.
w sortowaniu case nie jest potrzebny, ponieważ i tak wskazujesz tylko te rekordy z polem tovisit większym od 0
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
To w końcu 8 mln czy 10 tys rekordów?
Ile trwa wykonanie samego zapytania SQL?