sql >> Database >  >> RDS >> Mysql

Kan MySQL FIND_IN_SET of gelijkwaardig worden gemaakt om indices te gebruiken?

In verwijzing naar uw opmerking:

@MarcB de database is genormaliseerd, de CSV-string komt van de gebruikersinterface."Geef me gegevens voor de volgende mensen:101.202.303"

Dit antwoord heeft een beperkte focus op alleen die getallen gescheiden door een komma. Omdat, zo blijkt, je het niet eens had over FIND_IN_SET tenslotte.

Ja, je kunt bereiken wat je wilt. U maakt een voorbereide instructie die een tekenreeks als parameter accepteert, zoals in deze Recent antwoord van mij. Kijk in dat antwoord naar het tweede blok met de CREATE PROCEDURE en de 2e parameter die een string accepteert zoals (1,2,3) . Ik kom zo terug op dit punt.

Niet dat je het moet zien @spraff, maar anderen misschien. De missie is om het type . te krijgen !=ALL, en possible_keys en keys van Leg uit dat je null niet wilt laten zien, zoals je in je tweede blok hebt laten zien. Voor een algemene lezing over het onderwerp, zie het artikel Understanding Uitvoer UITLEG en de MySQL-handleidingpagina getiteld EXPLAIN Extra informatie .

Nu terug naar de (1,2,3) verwijzing hierboven. We weten uit uw opmerking en uw tweede Explain-output in uw vraag dat deze aan de volgende gewenste voorwaarden voldoet:

  1. type =bereik (en in het bijzonder niet ALLE) . Zie de documenten hierboven hierover.
  2. sleutel is niet null

Dit zijn precies de voorwaarden die je hebt in je tweede Explain-output, en de output die je kunt zien met de volgende query:

explain 
select * from ratings where id in (2331425, 430364, 4557546, 2696638, 4510549, 362832, 2382514, 1424071, 4672814, 291859, 1540849, 2128670, 1320803, 218006, 1827619, 3784075, 4037520, 4135373, ... use your imagination ..., ...,  4369522, 3312835);

waar ik 999 waarden heb in die in clausule lijst. Dat is een voorbeeld van dit antwoord van mij in Bijlage D genereert dan zo'n willekeurige reeks csv, omgeven door open en gesloten haakjes.

En let op de volgende Explain-output voor dat 999-element in onderstaande clausule:

Doelstelling behaald. Je bereikt dit met een opgeslagen proces vergelijkbaar met degene die ik eerder noemde in deze link met behulp van een PREPARED STATEMENT (en die dingen gebruiken concat() gevolgd door een EXECUTE ).

De index wordt gebruikt, een Tablescan (betekenis slecht) wordt niet ervaren. Verdere lezingen zijn Het bereik Join Type , elke referentie die u kunt vinden op MySQL's Cost-Based Optimizer (CBO), dit antwoord van vladr hoewel gedateerd, met het oog op de ANALYZE TABLE deel, met name na significante gegevenswijzigingen. Houd er rekening mee dat ANALYSE een aanzienlijke hoeveelheid tijd kan kosten om uit te voeren op ultra-enorme datasets. Soms vele vele uren.

Sql-injectie-aanvallen:

Het gebruik van tekenreeksen die worden doorgegeven aan opgeslagen procedures is een aanvalsvector voor SQL-injectieaanvallen. Er moeten voorzorgsmaatregelen worden getroffen om deze te voorkomen bij het gebruik van door de gebruiker aangeleverde gegevens. Als uw routine wordt toegepast op uw eigen id's die door uw systeem zijn gegenereerd, bent u veilig. Houd er echter rekening mee dat SQL-injectie-aanvallen op het tweede niveau plaatsvinden wanneer gegevens zijn ingevoerd door routines die die gegevens niet hebben opgeschoond in een eerdere invoeging of update. Aanvallen die vooraf via data zijn uitgevoerd en later worden gebruikt (een soort tijdbom).

Dit antwoord is dus Klaar voor het grootste deel.

Het onderstaande is een weergave van dezelfde tabel met een kleine wijziging om te laten zien wat een gevreesde Tablescan zou eruitzien als in de vorige zoekopdracht (maar tegen een niet-geïndexeerde kolom genaamd thing ).

Bekijk onze huidige tabeldefinitie:

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;

select min(id), max(id),count(*) as theCount from ratings;
+---------+---------+----------+
| min(id) | max(id) | theCount |
+---------+---------+----------+
|       1 | 5046213 |  4718592 |
+---------+---------+----------+

Merk op dat de kolom thing was eerder een nullable int-kolom.

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 where id>=3000000 and id<4000000;
update ratings set thing=id where id>=4000000 and id<5100000;
select count(*) from ratings where thing!=id;
-- 0 rows

ALTER TABLE ratings MODIFY COLUMN thing int not null;

-- current table definition (after above 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;

En dan de Explain that is a Tablescan (tegen kolom thing ):




  1. phpMyAdmin op MySQL 8.0

  2. Lopend totaal per groeps-SQL (Oracle)

  3. Inzicht in Always ON-beschikbaarheidsgroep tussen op Linux gebaseerde SQL Server-instanties. Deel 1

  4. Waarom is het uitvoeren van opgeslagen procedures sneller dan een SQL-query vanuit een script?