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ć?
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.
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 :-)
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
.
Może to Ci pomoże : https://github.com/StackExchange/Dapper
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
To w końcu 8 mln czy 10 tys rekordów?
Ile trwa wykonanie samego zapytania SQL?