Jak zopymalizowac zapytanie SELECT?

0

Witam,

Mam tabele tj event, artist i relacje pomiedzy nimi czyli event_artists (1 do *). Musze napisac zapytanie, ktore sprawdza czy relacja pomiedzy tymi tabelami istnieje. Czyli czy artysta istnieje juz w mojem bazie danych. Tabela:

Zaznaczam, ze jest to Postgresowa baza danych.

event_artists
eventId
artistId
position
type
artist_name

Zapytanie SQL:

SELECT count(eventId) FROM event_artists WHERE artistId IN('de2344st34') LIMIT 1;

Zastanawiam sie ktory operator szybciej dziala IN, ==, 'LIKE'. Druga sprawa jak utworzyc tutaj index?

0

EXISTS będzie najszybszy.
EDIT:
SELECT exists(SELECT * FROM event_artists WHERE artistId='de2344st34')

1

@Marcin.Miga: hm, no dobra. Co w momencie jak musze sprawdzic np 10 artystow? Bo w sumie chyba bedzie lepiej napisac jedno zapytanie wyciagnac artistId ktore istnieja i juz w backendzie sprawdzic co i jak. Tylko artistId bedzie sie powtarzal, to uzyc Distinct czy Group by? Wiem, ze to prosta, mala tabela. Ale tutaj musze napisac jak najszyvsze zapytanie + pewnie jakis index by sie przydal ;)

0

A po co chcesz to sprawdzać? Klucz obcy z EVENT_ARTISTS do ARTISTS da Ci odpowiedź przy insercie do EVENT_ARTISTS ;-)

0

@poniatowski: Napisz przykładowe zapytanie, jak chcesz sprawdzać...

0
SELECT artist_id
FROM eg_event_artists
WHERE artist_id IN ('dsf23', 'f3f34', 'f452esd', '493d4s3') 
GROUP BY artist_id;   
0

Poczekaj, ty chcesz mieć pewność, że dany artysta nie wystąpi 2 razy? Czy, że dany artysta nie będzie przypisany do jednego eventu dwukrotnie? W każdym z tych przypadków unikatowy indeks załatwi Ci sprawę.

0

Niestety, nic z tych rzeczy. W projekcie korzystam z API, ktore szuka mi artyste (autocomplete lists). No i tutaj jest problem, bo te API nie dzila zbyt dobrze, do tego chce zaoszczedzic na requestach do tego IP. Wiec, jak zapisuje nowa relacje (artyste) najpierw sprawdzam czy artistId istnieje w mojej DB, zeby nie wysylac dodatkowego requesto do tego API. Tylko, problem jest tego typu, ze ta tabelka ma sporo tysiecy rekordow. Wiec, chcialbym napisac jak najoptymalniejsze zapytanie.

0

A filtr Blooma nie sprawdziłby Ci się do takich zastosowań? Inicjalizowałbyś go przy starcie aplikacji i aktualizował przy dodawaniu elementów. Szybszy niż strzał do bazy ;-)

-- edited:
Kalkulator, który pozwoli oszacować ile taka struktura zeżarłaby pamięci: https://hur.st/bloomfilter/

1
/*
create table eg_event_artists
(
id bigint primary key,
artist_id varchar(10)
);

copy eg_event_artists from 'c://tmp//xx.csv' with csv  delimiter ';' header ;

-- xx.csv zawierało 100 tys losowych 5-cioznakowych stringów
*/

with a(aid) as(values
('cf6fa'),('de0e8'),('c7373'),('a5794'),('ce7e6'),('d5795')
)
select a.aid, e.* from a left join eg_event_artists e on a.aid=e.artist_id 
where e.artist_id is null

Bez WHERE czas 32 ms. Z WHERE ok.50 ms
Znajduje dwa NULLE

EXPLAIN VERBOSE:

Hash Anti Join  (cost=3280.07..3771.39 rows=1 width=46)
  Output: a.aid, e.id, e.artist_id
  Hash Cond: (a.aid = (e.artist_id)::text)
  CTE a
    ->  Values Scan on "*VALUES*"  (cost=0.00..0.08 rows=6 width=32)
          Output: "*VALUES*".column1
  ->  CTE Scan on a  (cost=0.00..0.12 rows=6 width=32)
        Output: a.aid
  ->  Hash  (cost=1541.00..1541.00 rows=100000 width=14)
        Output: e.id, e.artist_id
        ->  Seq Scan on public.eg_event_artists e  (cost=0.00..1541.00 rows=100000 width=14)
              Output: e.id, e.artist_id

po założeniu indeksu:

create index on eg_event_artists(artist_id)

Statystyka:

Nested Loop Anti Join  (cost=0.37..46.13 rows=1 width=46)
  Output: a.aid, e.id, e.artist_id
  CTE a
    ->  Values Scan on "*VALUES*"  (cost=0.00..0.08 rows=6 width=32)
          Output: "*VALUES*".column1
  ->  CTE Scan on a  (cost=0.00..0.12 rows=6 width=32)
        Output: a.aid
  ->  Index Scan using eg_event_artists_artist_id_idx on public.eg_event_artists e  (cost=0.29..8.31 rows=1 width=14)
        Output: e.id, e.artist_id
        Index Cond: (a.aid = (e.artist_id)::text)
1

@yarel:
Po założeniu HASH INDEX statystyka wygląda tak:

Nested Loop Anti Join  (cost=0.08..44.38 rows=1 width=46)
  Output: a.aid, e.id, e.artist_id
  CTE a
    ->  Values Scan on "*VALUES*"  (cost=0.00..0.08 rows=6 width=32)
          Output: "*VALUES*".column1
  ->  CTE Scan on a  (cost=0.00..0.12 rows=6 width=32)
        Output: a.aid
  ->  Index Scan using hashed_idx on public.eg_event_artists e  (cost=0.00..8.02 rows=1 width=14)
        Output: e.id, e.artist_id
        Index Cond: (a.aid = (e.artist_id)::text)

Czasy wykonania mniej więcej takie same... (może z WHERE trochę szybsze)

1 użytkowników online, w tym zalogowanych: 0, gości: 1