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

Výkon MySQL:více tabulek vs. index na jedné tabulce a oddílech

Vytvořit 20 000 tabulek je špatný nápad. Zanedlouho budete potřebovat 40 000 stolů a pak ještě více.

Tento syndrom jsem nazval Metadata Tribbles v mé knize SQL Antipatterns . To uvidíte pokaždé, když plánujete vytvořit „tabulku na X“ nebo „sloupec na X“.

To způsobuje skutečné problémy s výkonem, když máte desítky tisíc tabulek. Každá tabulka vyžaduje, aby MySQL udržovala interní datové struktury, deskriptory souborů, datový slovník atd.

Má to i praktické provozní důsledky. Opravdu chcete vytvořit systém, který vyžaduje vytvoření nové tabulky pokaždé, když se zaregistruje nový uživatel?

Místo toho bych vám doporučil použít MySQL Partitioning .

Zde je příklad rozdělení tabulky:

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;

To vám dává výhodu definování jedné logické tabulky a zároveň rozdělení tabulky do mnoha fyzických tabulek pro rychlejší přístup při dotazu na konkrétní hodnotu klíče oddílu.

Když například spustíte dotaz, jako je váš příklad, MySQL přistupuje pouze ke správnému oddílu obsahujícímu konkrétní user_id:

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

Metoda HASH rozdělení znamená, že řádky jsou umístěny v oddílu pomocí modulu klíče rozdělení celého čísla. To znamená, že mnoho uživatelských id se mapuje na stejný oddíl, ale každý oddíl by měl v průměru pouze 1/Nth tolik řádků (kde N je počet oddílů). A definujete tabulku s konstantním počtem oddílů, takže ji nemusíte rozšiřovat pokaždé, když získáte nového uživatele.

Můžete si vybrat libovolný počet oddílů až do 1024 (nebo 8192 v MySQL 5.6), ale někteří lidé hlásili problémy s výkonem, když jdou tak vysoko.

Doporučuje se použít prvočíslo oddílů. V případě, že se vaše hodnoty user_id řídí vzorem (jako je použití pouze sudých čísel), použití prvočíselného počtu oddílů pomáhá distribuovat data rovnoměrněji.

Zopakujte své otázky v komentářích:

Pokud pro rozdělování HASH použijete 101 oddílů, jak uvádím v příkladu výše, pak každý daný oddíl má v průměru asi 1 % vašich řádků. Řekl jste, že vaše tabulka statistik má 30 milionů řádků, takže pokud použijete toto rozdělení, budete mít pouze 300 tisíc řádků na oddíl. To je pro MySQL mnohem snazší přečíst. Můžete (a měli byste) také používat indexy -- každý oddíl bude mít svůj vlastní index a bude pouze o 1 % větší, než by byl index v celé nerozdělené tabulce.

Takže odpověď na to, jak můžete určit rozumný počet oddílů, je:jak velká je celá vaše tabulka a jak velké chcete, aby byly oddíly v průměru?

Pokud používáte HASH rozdělení, počet oddílů nemusí nutně růst. Nakonec můžete mít celkem 30 miliard řádků, ale zjistil jsem, že když objem vašich dat naroste o řády, vyžaduje to stejně novou architekturu. Pokud jsou vaše data tak velká, pravděpodobně budete potřebovat sharding přes více serverů a také rozdělení do více tabulek.

To znamená, že můžete znovu rozdělit tabulku pomocí ALTER TABLE:

ALTER TABLE statistics PARTITION BY HASH(user_id) PARTITIONS 401;

To musí restrukturalizovat tabulku (jako většina změn ALTER TABLE), takže počítejte s tím, že to chvíli potrvá.

Možná budete chtít sledovat velikost dat a indexů v oddílech:

SELECT table_schema, table_name, table_rows, data_length, index_length
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE partition_method IS NOT NULL;

Stejně jako u jakékoli tabulky chcete, aby se celková velikost aktivních indexů vešla do vaší oblasti vyrovnávacích pamětí, protože pokud MySQL musí během SELECT dotazů zaměňovat části indexů v oblasti vyrovnávacích pamětí a ven z ní, výkon trpí.

Pokud používáte dělení na RANGE nebo LIST, pak je přidávání, rušení, slučování a rozdělování oddílů mnohem běžnější. Viz http://dev.mysql. com/doc/refman/5.6/en/partitioning-management-range-list.html

Doporučuji vám přečíst si příruční sekci o dělení a podívejte se také na tuto pěknou prezentaci:Zvýšení výkonu S oddíly MySQL 5.1 .



  1. Jak filtrovat výsledky SQL ve vztahu has-many-through

  2. Jak nasadit PostgreSQL pro vysokou dostupnost

  3. nahrávání obrázků na server v jarním MVC a ukládání referencí do databáze mysql

  4. Výkon MySQL:Úvod do JOINů v SQL