sql >> Databáze >  >> RDS >> Mysql

Lze MySQL FIND_IN_SET nebo ekvivalent nastavit tak, aby používal indexy?

S odkazem na váš komentář:

@MarcB databáze je normalizovaná, řetězec CSV pochází z uživatelského rozhraní." Získat data pro následující lidi:101,202,303"

Tato odpověď se úzce zaměřuje pouze na čísla oddělená čárkou. Protože, jak se ukázalo, jste ani nemluvili o FIND_IN_SET koneckonců.

Ano, můžete dosáhnout toho, co chcete. Vytvoříte připravený příkaz, který akceptuje řetězec jako parametr, jako v tomto Nedávná odpověď můj. V této odpovědi se podívejte na druhý blok, který ukazuje CREATE PROCEDURE a jeho 2. parametr, který přijímá řetězec jako (1,2,3) . K tomuto bodu se za chvíli vrátím.

Ne že byste to potřebovali vidět @spraff, ale ostatní by to mohli vidět. Úkolem je získat typ !=ALL a možné_klíče a klíče of Explain, aby se nezobrazovala hodnota null, jak jste ukázali ve svém druhém bloku. Obecné informace o tématu naleznete v článku Porozumění Výstup EXPLAIN a stránka s příručkou MySQL s názvem EXPLAIN Další informace .

Nyní zpět k (1,2,3) odkaz výše. Z vašeho komentáře a vašeho druhého výstupu Explain ve vaší otázce víme, že splňuje následující požadované podmínky:

  1. typ =rozsah (a zejména ne VŠECHNY) . Viz výše uvedené dokumenty.
  2. klíč není prázdný

Toto jsou přesně podmínky, které máte ve svém druhém výstupu Explain, a výstup, který lze zobrazit pomocí následujícího dotazu:

Vysvětlete vyberte * z hodnocení, kde ID v (2331425, 430364, 4557546, 2696638, 4510549, 362832, 2382514, 1424071, 46728, 15430, 1322763, 2180, 1322763, 2180, 1322763, 2180, 21206333, 212, 212833, 212, 2128333, 2918633330, 2918633330, 2918633330, 2918633330, 29186333, 29186333, 29186333, 29186333, 29186333, 291863, 46333, 291859. , ... použijte svou fantazii ..., ..., 4369522, 3312835);

kde mám 999 hodnot v tom in seznam doložek. Toto je ukázka z této odpovědi mého v příloze D, než vygeneruje takový náhodný řetězec csv, obklopený otevřenými a uzavřenými závorkami.

A všimněte si následujícího výstupu Explain pro tento prvek 999 v klauzuli níže:

Cíl splněn. Dosáhnete toho pomocí uloženého procesu podobného tomu, který jsem zmínil dříve v tomto odkazu pomocí PŘIPRAVENÉ PROHLÁŠENÍ (a tyto věci používají concat() následuje EXECUTE ).

Index se používá, Tablescan (což znamená špatný) není zažíván. Další údaje jsou Typ spojení rozsahu , jakoukoli referenci, kterou můžete najít v MySQL's Cost-Based Optimizer (CBO), tato odpověď od vladra, ačkoli datovaný, s okem na ANALYZE TABLE část, zejména po významných změnách údajů. Mějte na paměti, že ANALYZE může trvat značnou dobu, než se spustí na velmi rozsáhlých souborech dat. Někdy mnoho hodin.

Sql Injection Attacks:

Použití řetězců předávaných uloženým procedurám je vektorem útoku pro útoky SQL Injection. Při používání dat dodaných uživatelem musí být přijata opatření, která jim zabrání. Pokud je vaše rutina použita proti vašemu vlastnímu ID generovanému vaším systémem, pak jste v bezpečí. Všimněte si však, že k útokům SQL Injection 2. úrovně dochází, když byla data vložena na místo rutinami, které tato data nedezinfikovaly při předchozím vložení nebo aktualizaci. Útoky provedené dříve prostřednictvím dat a použité později (jakási časovaná bomba).

Takže tato odpověď je Dokončeno z větší části.

Níže je pohled na stejnou tabulku s drobnými úpravami, aby bylo vidět, co je obávaný Tablescan by vypadalo jako v předchozím dotazu (ale proti neindexovanému sloupci s názvem thing ).

Podívejte se na naši aktuální definici tabulky:

CREATE TABLE `ratings` ( `id` int(11) NOT NULL AUTO_INCREMENT, `thing` int(11) DEFAULT NULL, PRIMAR KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=5046214 DEFAULT CHARSET=utf8;vyberte min(id), max(id),count(*) jako Počet z hodnocení;+---------+---------+-------- ---+| min(id) | max(id) | theCount |+---------+---------+----------+| 1 | 5046213 | 4718592 |+---------+---------+----------+ 

Všimněte si, že sloupec věc byl předtím sloupec typu int s možnou hodnotou Null.

aktualizovat hodnocení nastavit věc=id kde id<1000000;aktualizovat nastavit hodnocení věci=id kde id>=1000000 a id<2000000;aktualizovat hodnocení nastavit věc=id kde id>=2000000 a id<3000000;aktualizovat hodnocení nastavit věc=id kde id>=3000000 a id<4000000;aktualizovat nastavení hodnocení věci=id kde id>=4000000 a id<5100000;vybrat počet(*) z hodnocení kde věc!=id;-- 0 řádků ALTER TABLE hodnocení MODIFY COLUMN thing int not null;-- aktuální definice tabulky (po výše ALTER):CREATE TABLE `ratings` ( `id` int(11) NOT NULL AUTO_INCREMENT, `thing` int(11) NOT NULL, PRIMARY KEY (`id `)) ENGINE=InnoDB AUTO_INCREMENT=5046214 DEFAULT CHARSET=utf8; 

A pak Explain, což je Tablescan (proti sloupci thing ):




  1. Vypočítejte rozdíl mezi dvěma daty a časy v MySQL

  2. Výstup výsledků dotazu SQLite jako příkaz INSERT

  3. Změní se ID prostředku při každém spuštění aplikace

  4. Převeďte název měsíce na číslo měsíce v PostgreSQL