it-swarm-eu.dev

Co je efektivnější, klauzule where nebo spojení s miliony plus řádkovými tabulkami?

Provozujeme web, který má 250MM řádků v jedné tabulce a v jiné tabulce, ke které se připojujeme, je pro většinu dotazů těsně pod 15MM řádků.

Ukázkové struktury:

MasterTable (Id, UserId, Created, Updated...) -- 15MM Rows
DetailsTable (Id, MasterId, SomeColumn...) -- 250MM Rows
UserTable (Id, Role, Created, UserName...) -- 12K Rows

Proti všem těmto tabulkám musíme pravidelně dělat několik dotazů. Jedním z nich je grabování statistik pro bezplatné uživatele (~ 10 tisíc uživatelů zdarma).

Select Count(1) from DetailsTable dt 
join MasterTable mt on mt.Id = dt.MasterId 
join UserTable ut on ut.Id = mt.UserId 
where ut.Role is null and mt.created between @date1 and @date2

Problém je, že tento dotaz bude někdy trvat dlouhou zatracenou dobu kvůli skutečnosti, že spojení se stane dlouho před tím, kde.

V tomto případě by bylo moudřejší použít místo spojení a případně where column in(...)?

20
Jeremy Boyd

U moderních RDBMS není rozdíl mezi "explicitním připojením" a "připojením", pokud jsou všechny připojené položky VNITŘNÍ, pokud jde o výkon a plán dotazů.

Explicitní syntaxe JOIN je jasnější a méně nejednoznačná (viz odkazy níže)

Nyní JOIN-before-WHERE je logické zpracování, které není skutečné zpracování a moderní optimalizátoři jsou dost chytří, aby si to uvědomili.

Váš problém je s největší pravděpodobností indexování.

Ukážte nám prosím všechny indexy a klíče v těchto tabulkách. A plány dotazů

Poznámka: Tato otázka by byla na StackOverflow velmi blízká, protože by to byl duplikát ... COUNT (1) vs. COUNT (*) je další mýtus.

20
gbn

Dotaz musíte zcela změnit

Zkuste provést klauzule WHERE dříve a JOIN později

Select Count(1) from DetailsTable dt
join (Select UserId,Id FROM MasterTable where
created between @date1 and @date2) mt on mt.Id = dt.MasterId 
join (Select Id FROM UserTable WHERE Role is NULL) ut
on ut.Id = mt.UserId;

I když spustíte plán EXPLAIN pro tento refactored dotaz a vypadá to horší, než váš původní, zkuste to stejně. Intervalové tabulky vytvořené interně provedou kartézské spojení, ale tyto tabulky jsou menší, se kterými lze pracovat.

Tento nápad jsem dostal z tohoto videa YouTube .

Vyzkoušel jsem principy z videa ve velmi složité otázce v StackOverflow a dostal jsem 200 bodových odměn.

@gbn zmínil, že máte správné indexy. V takovém případě prosím vytvořený sloupec indexujte v tabulce MasterTable.

Pokusit se !!!

AKTUALIZACE 2011-06-24 22:31 EDT

Měli byste spustit tyto dotazy:

SELECT COUNT(1) AllRoles FROM UserTable;
SELECT COUNT(1) NullRoles FROM UserTable WHERE Role is NULL;

Pokud NullRoles X 20 <AllRoles (jinými slovy, pokud NullRoles je menší než 5% řádků tabulky), měli byste vytvořit neunikátní index Role v UserTable. V opačném případě by stačila celá tabulka UserTable, protože Optimalizátor dotazů by možná vyloučil použití indexu.

UPDATE 2011-06-25 12:40 EDT

Vzhledem k tomu, že jsem MySQL DBA, vyžaduje můj způsob, jak dělat věci, nedůvěřovat Optimalizátoru dotazů MySQL prostřednictvím pozitivního pesimismu a konzervativnosti. Pokusím se tedy refactorovat dotaz nebo vytvořit potřebné krycí indexy, abychom se dostali před skryté špatné návyky nástroje MySQL Query Optimizer. Odpověď @ gbn se zdá být úplnější v tom, že SQL Server může mít více dotazů na "zdravost mysli".

6
RolandoMySQLDBA

Měli jsme [Detail] tabulku o 75M řadách; tabulka [Master] o 400 000 řádcích a související tabulka [Item], která měla vždy 7 řádků vždy a navždy. Ukládal malou sadu „čísel položek“ (1-7) a modeloval papírovou formu, z níž byly každý měsíc vytištěny a distribuovány miliony. Nejrychlejším dotazem byl ten, o kterém byste si nejdříve mysleli, že se jedná o karteziánské spojení. IIRC, bylo to něco jako:

SELECT m.order_id, i.line_nr, d.Item_amt
FROM Master m, Item i 
INNER JOIN Detail d ON m.order_id = d.order_id

Přestože mezi položkami [Item] a [Detail] existuje logické „id“ propojení, CROSS JOIN fungoval lépe než INNER JOIN.

RDBMS byla Teradata s technologií MPP a IDR, co bylo schéma indexování. Tabulka se 7 řádky neměla žádný index, protože TABULKA SKENOVÁNÍ vždy vedla to nejlepší.

1
Timothy Oleary