Med henvisning til din kommentar:
@MarcB databasen er normaliseret, CSV-strengen kommer fra brugergrænsefladen."Få mig data for følgende personer:101.202.303"
Dette svar har et snævert fokus på netop de tal adskilt af et komma. Fordi, som det viser sig, talte du ikke engang om FIND_IN_SET
trods alt.
Ja, du kan opnå, hvad du vil. Du opretter en forberedt erklæring, der accepterer en streng som en parameter som i dette Seneste svar
af mine. I det svar skal du se på den anden blok, der viser CREATE PROCEDURE
og dens 2. parameter, som accepterer en streng som (1,2,3)
. Jeg vender tilbage til dette punkt om et øjeblik.
Ikke at du behøver at se det @spraff, men andre kan måske. Missionen er at få typen
!=ALLE og mulige_nøgler
og nøgler
af Forklar ikke at vise null, som du viste i din anden blok. For en generel læsning om emnet, se artiklen Forståelse EXPLAIN's output
og MySQL-manualsiden med titlen EXPLAIN Ekstra information
.
Nu tilbage til (1,2,3)
reference ovenfor. Vi ved fra din kommentar og dit andet Forklar-output i dit spørgsmål, at det opfylder følgende ønskede betingelser:
- type =område (og især ikke ALLE) . Se dokumenterne ovenfor om dette.
- nøglen er ikke null
Det er præcis de betingelser, du har i dit andet Explain-output, og det output, der kan ses med følgende forespørgsel:
Vælg * fra ratings, hvor ID i (2331425, 430364, 4557546, 269638, 4510549, 430364, 4557546, 269638, 4510549, 430364, 4557546, 269638 , ... brug din fantasi ..., ..., 4369522, 3312835);
hvor jeg har 999 værdier i den in
klausulliste. Det er et eksempel fra dette svar
af mine i appendiks D, så genererer en sådan tilfældig streng af csv, omgivet af åbne og lukkede parenteser.
Og bemærk følgende Forklar output for det 999-element i klausulen nedenfor:
Mål nået. Du opnår dette med en lagret proc, der ligner den, jeg nævnte før i dette link
ved hjælp af en FORBEREDT UDTALELSE
(og disse ting bruger concat()
efterfulgt af en EXECUTE
).
Indekset er brugt, en Tablescan (betyder dårligt) opleves ikke. Yderligere læsninger er The range Join Type
, enhver reference du kan finde på MySQL's Cost-Based Optimizer (CBO), dette svar
fra vladr dog dateret, med øje på ANALYSE TABEL
del, især efter væsentlige dataændringer. Bemærk, at ANALYSE kan tage en betydelig mængde tid at køre på ultra-store datasæt. Nogle gange mange mange timer.
Sql-injektionsangreb:
Brug af strenge, der sendes til Stored Procedures, er en angrebsvektor for SQL Injection-angreb. Forholdsregler skal være på plads for at forhindre dem ved brug af brugerleverede data. Hvis din rutine anvendes mod dine egne id'er genereret af dit system, så er du sikker. Bemærk dog, at SQL Injection-angreb på 2. niveau forekommer, når data blev sat på plads af rutiner, der ikke rensede disse data i en tidligere indsættelse eller opdatering. Angreb på plads forud for via data og brugt senere (en slags tidsindstillet bombe).
Så dette svar er færdig for det meste.
Nedenstående er en visning af den samme tabel med en mindre ændring af den for at vise, hvad en frygtet Tablescan ville se ud som i den foregående forespørgsel (men mod en ikke-indekseret kolonne kaldet thing
).
Ta et kig på vores nuværende tabeldefinition:
CREATE TABLE `ratings` ( `id` int(11) NOT NULL AUTO_INCREMENT, `thing` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=5046214 DEFAULT CHARSET=utf8;vælg min(id), max(id),count(*) som Count fra ratings;+---------+--------+------- ---+| min(id) | max(id) | theCount |+--------+---------+----------+| 1 | 5046213 | 4718592 |+---------+--------+---------+
Bemærk, at kolonnen thing
var en nullbar int-kolonne før.
update ratings set thing=id where id<1000000;update ratings set thing=id where id>=1000000 and id<2000000;update ratings set thing=id where id>=2000000 and id<3000000;update ratings set thing=id hvor id>=3000000 og id<4000000;opdater ratings set thing=id hvor id>=4000000 og id<5100000;vælg count(*) fra vurderinger hvor thing!=id;-- 0 rowsALTER TABLE ratings MODIFY COLUMN thing int not null;-- nuværende tabeldefinition (efter ovenstående 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;
Og så Forklar, der er en Tablescan (mod kolonne thing
):