Het maken van 20.000 tabellen is een slecht idee. Binnenkort heb je 40.000 tafels nodig, en dan nog meer.
Ik noemde dit syndroom Metadata Tribbles in mijn boek SQL Antipatterns . Je ziet dit elke keer gebeuren als je van plan bent een "tabel per X" of een "kolom per X" te maken.
Dit veroorzaakt echte prestatieproblemen als je tienduizenden tabellen hebt. Elke tabel vereist MySQL om interne gegevensstructuren, bestandsdescriptors, een datadictionary, enz. te onderhouden.
Er zijn ook praktische operationele consequenties. Wil je echt een systeem maken waarbij je elke keer dat een nieuwe gebruiker zich aanmeldt een nieuwe tabel moet maken?
In plaats daarvan raad ik u aan MySQL-partitionering te gebruiken .
Hier is een voorbeeld van het partitioneren van de tabel:
CREATE TABLE statistics (
id INT AUTO_INCREMENT NOT NULL,
user_id INT NOT NULL,
PRIMARY KEY (id, user_id)
) PARTITION BY HASH(user_id) PARTITIONS 101;
Dit geeft u het voordeel dat u één logische tabel definieert, terwijl u de tabel ook in veel fysieke tabellen verdeelt voor snellere toegang wanneer u een specifieke waarde van de partitiesleutel opvraagt.
Als u bijvoorbeeld een query uitvoert zoals uw voorbeeld, heeft MySQL alleen toegang tot de juiste partitie die de specifieke user_id bevat:
mysql> EXPLAIN PARTITIONS SELECT * FROM statistics WHERE user_id = 1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: statistics
partitions: p1 <--- this shows it touches only one partition
type: index
possible_keys: NULL
key: PRIMARY
key_len: 8
ref: NULL
rows: 2
Extra: Using where; Using index
De HASH-methode van partitionering betekent dat de rijen in een partitie worden geplaatst door een modulus van de integer partitiesleutel. Dit betekent wel dat veel user_id's naar dezelfde partitie zijn toegewezen, maar dat elke partitie gemiddeld slechts 1/N-de zoveel rijen zou hebben (waarbij N het aantal partities is). En u definieert de tabel met een constant aantal partities, zodat u deze niet telkens hoeft uit te breiden als u een nieuwe gebruiker krijgt.
Je kunt een willekeurig aantal partities kiezen tot 1024 (of 8192 in MySQL 5.6), maar sommige mensen hebben prestatieproblemen gemeld als ze zo hoog gaan.
Het wordt aanbevolen om een priemgetal partities te gebruiken. Als uw user_id-waarden een patroon volgen (zoals het gebruik van alleen even getallen), helpt het gebruik van een priemgetal partities de gegevens gelijkmatiger te verdelen.
Re uw vragen in commentaar:
Voor HASH-partitionering, als je 101 partities gebruikt zoals ik in het bovenstaande voorbeeld laat zien, dan heeft elke partitie gemiddeld ongeveer 1% van je rijen. U zei dat uw statistiektabel 30 miljoen rijen heeft, dus als u deze partitionering gebruikt, zou u slechts 300k rijen per partitie hebben. Dat is veel gemakkelijker voor MySQL om door te lezen. U kunt (en moet) ook indexen gebruiken -- elke partitie heeft zijn eigen index en deze zal slechts 1% zo groot zijn als de index op de hele niet-gepartitioneerde tabel zou zijn.
Dus het antwoord op hoe je een redelijk aantal partities kunt bepalen is:hoe groot is je hele tafel en hoe groot wil je dat de partities gemiddeld zijn?
Het aantal partities hoeft niet per se te groeien als u HASH-partitionering gebruikt. Uiteindelijk heb je misschien in totaal 30 miljard rijen, maar ik heb ontdekt dat wanneer je datavolume in orde van grootte groeit, dat sowieso een nieuwe architectuur vereist. Als uw gegevens zo groot worden, heeft u waarschijnlijk sharding nodig over meerdere servers en ook over meerdere tabellen.
Dat gezegd hebbende, je kunt een tabel opnieuw partitioneren met ALTER TABLE:
ALTER TABLE statistics PARTITION BY HASH(user_id) PARTITIONS 401;
Dit moet de tabel herstructureren (zoals de meeste ALTER TABLE-wijzigingen), dus verwacht dat het even kan duren.
Misschien wilt u de grootte van gegevens en indexen in partities controleren:
SELECT table_schema, table_name, table_rows, data_length, index_length
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE partition_method IS NOT NULL;
Zoals bij elke tabel, wil je dat de totale grootte van actieve indexen in je bufferpool past, want als MySQL delen van indexen in en uit de bufferpool moet verwisselen tijdens SELECT-query's, lijden de prestaties eronder.
Als u RANGE- of LIST-partitionering gebruikt, is het toevoegen, verwijderen, samenvoegen en splitsen van partities veel gebruikelijker. Zie http://dev.mysql. com/doc/refman/5.6/en/partitioning-management-range-list.html
Ik moedig u aan om de handmatige sectie over partitionering te lezen , en bekijk ook deze mooie presentatie:Boost Performance Met MySQL 5.1-partities .