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

Zrychlete MySQL Update/Insert Statement

Pokud to potřebujete udělat milionkrát, je tu spousta problémů s výkonem.

  • Připravujete stejný příkaz SQL znovu a znovu, milionkrát. Bylo by lepší to připravit jednou a spustit milionkrát.

  • Odpojujete se od databáze při každém volání funkce po jediném dotazu. To znamená, že se musíte pokaždé znovu připojit a veškeré informace uložené v mezipaměti budou zahozeny. Nedělejte to, nechte to připojené.

  • Po každém řádku se zavazujete. Tím se věci zpomalí. Místo toho proveďte potvrzení po provedení dávky.

  • Select + update nebo insert lze pravděpodobně provést jako jeden upsert.

  • To, že toho do dočasné tabulky vkládáte tolik, je pravděpodobně problém s výkonem.

  • Pokud má tabulka příliš mnoho indexů, může to zpomalit vkládání. Někdy je nejlepší indexy vypustit, provést velkou dávkovou aktualizaci a znovu je vytvořit.

  • Protože vkládáte hodnoty přímo do svého SQL, váš SQL je otevřen útoku SQL injection .

Místo toho...

  • Používejte připravené příkazy a parametry vazby
  • Nechte databázi připojenou
  • Hromadné aktualizace
  • Potvrdit pouze na konci běhu aktualizací
  • Proveďte všechny výpočty v UPDATE spíše než SELECT + math + UPDATE .
  • Namísto SELECT použijte "UPSERT". poté UPDATE nebo INSERT

Nejprve připravená prohlášení. Ty umožňují MySQL jednou zkompilovat příkaz a poté jej znovu použít. Cílem je napsat prohlášení se zástupnými symboly pro hodnoty.

select id, position, impressions, clicks, ctr
from temp
where profile_id=%s and
      keyword=%s and 
      landing_page=%s

Potom to provedete s hodnotami jako argumenty, nikoli jako součást řetězce.

self.cursor.execute(
   'select id, position, impressions, clicks, ctr from temp where profile_id=%s and keyword=%s and landing_page=%s',
   (profile_id, keyword, landing_page)
)

To umožňuje databázi uložit připravený příkaz do mezipaměti a nemusí jej pokaždé znovu kompilovat. Také se vyhne útoku SQL injection, kdy chytrý útočník může vytvořit hodnotu, která je ve skutečnosti spíše SQL jako " MORE SQL HERE " . Je to velmi, velmi, velmi častá bezpečnostní díra.

Poznámka:Možná budete muset použít vlastní MySQL Knihovna databáze Python pro získání pravdivých připravených příkazů . Příliš si s tím nedělejte starosti, používání připravených příkazů není vaším největším výkonnostním problémem.

Dále to, co v podstatě děláte, je přidání do existujícího řádku, nebo pokud neexistuje žádný existující řádek, vložení nového. To lze provést efektivněji v jediném příkazu pomocí UPSERT , kombinovaný INSERT a UPDATE . MySQL to má jako INSERT ... ON DUPLICATE KEY UPDATE .

Chcete-li vidět, jak se to dělá, můžeme napsat váš SELECT then UPDATE jako jeden UPDATE . Výpočty se provádějí v SQL.

    update temp
    set impressions = impressions + %s,
        clicks = clicks + %s,
        ctr = (ctr + %s / 2)
    where profile_id=%s and
          keyword=%s and
          landing_page=%s

Váš INSERT zůstává stejný...

    insert into temp
        (profile_id, landing_page, keyword, position, impressions, clicks, ctr)
        values (%s, %s, %s, %s, %s, %s, %s)

Spojte je do jednoho INSERT ON DUPLICATE KEY UPDATE.

    insert into temp
        (profile_id, landing_page, keyword, position, impressions, clicks, ctr)
        values (%s, %s, %s, %s, %s, %s, %s)
    on duplicate key update
    update temp
    set impressions = impressions + %s,
        clicks = clicks + %s,
        ctr = (ctr + %s / 2)

To závisí na tom, jak jsou definovány klíče tabulky. Pokud máte unique( profile_id, landing_page, keyword ) pak by to mělo fungovat stejně jako váš kód.

I když nemůžete udělat upsert, můžete odstranit SELECT pomocí UPDATE , zkontroluje, zda něco aktualizoval a zda neprovedl INSERT .

Provádějte aktualizace hromadně. Místo volání podprogramu, který provede jednu aktualizaci a provede potvrzení, předejte mu velký seznam věcí, které mají být aktualizovány, a pracujte na nich ve smyčce. Můžete dokonce využít výhod executemany spustit stejný příkaz s více hodnotami. Poté potvrďte.

Možná budete moci provést UPSERT hromadně. INSERT může mít více řádků najednou. Například tím vložíte tři řádky.

insert into whatever
    (foo, bar, baz)
values (1, 2, 3),
       (4, 5, 6), 
       (7, 8, 9)

Pravděpodobně můžete udělat totéž pomocí INSERT ON DUPLICATE KEY UPDATE snížení režijních nákladů na komunikaci s databází. Příklad viz tento příspěvek (v PHP, ale měli byste být schopni se přizpůsobit).

To obětuje vrácení ID posledního vloženého řádku, ale to jsou konce.




  1. Kontrola zaškrtávacích políček z databázových hodnot

  2. Jak ručně nastavit počáteční hodnotu na 1000 v MySQL

  3. Rozsah dočasných tabulek v SQL Server

  4. Jak mohu samostatně počítat a seskupovat sloupce pomocí MySQL?