Geen van de twee voorgestelde oplossingen is waarschijnlijk optimaal, MAAR oplossing 1 is ONVOORSPELBAAR en dus INHERENT GEBREKKIG!
Een van de eerste dingen die je leert als je met grote databases werkt, is dat 'de beste manier' om een zoekopdracht uit te voeren vaak afhankelijk is van factoren (ook wel metadata genoemd) in de database:
- Hoeveel rijen er zijn.
- Hoeveel tabellen u opvraagt.
- De grootte van elke rij.
Hierdoor is het onwaarschijnlijk dat er een wonderbaarlijke oplossing voor uw probleem is. Uw database is niet hetzelfde als mijn database, u zult verschillende optimalisaties moeten benchmarken als u de best beschikbare prestaties nodig heeft.
U zult waarschijnlijk merken dat correcte indexen toepast en bouwt (en het begrijpen van de native implementatie van indexen in MySQL) in uw database doet veel meer voor u.
Er zijn enkele gouden regels voor zoekopdrachten die zelden mogen worden overtreden:
- Doe ze niet in lusstructuren . Hoe verleidelijk het vaak ook is, de overhead bij het maken van een verbinding, het uitvoeren van een query en het krijgen van een reactie is hoog.
- Vermijd
SELECT *
tenzij nodig . Het selecteren van meer kolommen zal de overhead van uw SQL-bewerkingen aanzienlijk verhogen. - Ken uw indexen . Gebruik de
EXPLAIN
functie zodat u kunt zien welke indexen worden gebruikt, uw zoekopdrachten kunt optimaliseren om te gebruiken wat beschikbaar is en nieuwe kunt maken.
Daarom zou ik van de twee voor de tweede query gaan (ter vervanging van SELECT *
met alleen de gewenste kolommen), maar er zijn waarschijnlijk betere manieren om de zoekopdracht te structureren als je de tijd hebt om te optimaliseren.
Snelheid mag echter NIET wees hierin je enige overweging, er is een GEWELDIGE reden om suggestie één niet te gebruiken:
VOORSPELBAARHEID:waarom leesvergrendelingen een goede zaak zijn
Een van de andere antwoorden suggereert dat het een slechte zaak is om de tafel voor een lange periode te vergrendelen, en dat daarom de oplossing met meerdere zoekopdrachten goed is.
Ik zou zeggen dat dit niet verder van de waarheid kan zijn . Sterker nog, ik zou zeggen dat in veel gevallen de voorspelbaarheid van het uitvoeren van een enkelvoudige SELECT
query is een groter argument VOOR het uitvoeren van die query dan de voordelen voor optimalisatie en snelheid.
Allereerst, wanneer we een SELECT
. uitvoeren (alleen-lezen) query op een MyISAM- of InnoDB-database (standaardsystemen voor MySQL), wat er gebeurt, is dat de tabel read-locked is. Dit voorkomt dat er schrijfbewerkingen op de tafel plaatsvinden totdat de leesvergrendeling is opgeheven (ofwel onze SELECT
query wordt voltooid of mislukt). Overig SELECT
zoekopdrachten worden niet beïnvloed, dus als u een toepassing met meerdere threads gebruikt, blijven ze werken.
Deze vertraging is een goede zaak. Waarom, vraagt u zich misschien af? Relationele gegevensintegriteit.
Laten we een voorbeeld nemen:we voeren een operatie uit om een lijst met items te krijgen die momenteel in de inventaris van een aantal gebruikers van een game zitten, dus we doen deze join:
SELECT * FROM `users` JOIN `items` ON `users`.`id`=`items`.`inventory_id` WHERE `users`.`logged_in` = 1;
Wat gebeurt er als een gebruiker tijdens deze zoekbewerking een item ruilt met een andere gebruiker? Met behulp van deze zoekopdracht zien we de spelstatus zoals deze was toen we de zoekopdracht startten:het item bestaat één keer, in de inventaris van de gebruiker die het had voordat we de zoekopdracht uitvoerden.
Maar wat gebeurt er als we het in een lus laten lopen?
Afhankelijk van of de gebruiker het heeft geruild voordat of nadat we zijn gegevens hebben gelezen, en in welke volgorde we de inventaris van de twee spelers lezen, zijn er vier mogelijkheden:
- Het item kan worden weergegeven in de inventaris van de eerste gebruiker (scan gebruiker B -> scan gebruiker A -> verhandeld item OF scan gebruiker B -> scan gebruiker A -> verhandeld item).
- Het item kan worden weergegeven in de inventaris van de tweede gebruiker (geruild item -> scan gebruiker A -> scan gebruiker B OF verhandeld item -> scan gebruiker B -> scan gebruiker A).
- Het item kan worden weergegeven in beide voorraden (scan gebruiker A -> verhandeld item -> scan gebruiker B).
- Het item kan worden weergegeven in geen van beide van de voorraden van de gebruiker (scan gebruiker B -> verhandeld item -> scan gebruiker A).
Dit betekent dat we niet in staat zouden zijn om de resultaten van de zoekopdracht te voorspellen of om relationele integriteit te garanderen .
Als je van plan bent om dinsdag om middernacht $ 5.000 te geven aan de man met item-ID 1000000, hoop ik dat je $ 10k bij de hand hebt. Als uw programma erop vertrouwt dat unieke items uniek zijn wanneer snapshots worden gemaakt, maakt u mogelijk een uitzondering met dit soort zoekopdracht.
Vergrendelen is goed omdat het de voorspelbaarheid verhoogt en beschermt de integriteit van resultaten.
Opmerking:je zou een lus kunnen forceren om te vergrendelen met een transactie , maar het zal nog langzamer zijn.
O, en tot slot, GEBRUIK VOORGESTELDE VERKLARINGEN!
Je moet nooit een verklaring hebben die er als volgt uitziet:
mysqli_query("SELECT * FROM Table2 WHERE ColumnAId=" . $row['ColumnAId'], $con);
mysqli
heeft ondersteuning voor voorbereide verklaringen
. Lees erover en gebruik ze, ze zullen u helpen voorkomen dat iets vreselijks met uw database gebeurt
.