sql >> Database >  >> RDS >> Oracle

INSERT van 10 miljoen queries binnen 10 minuten in Oracle?

Ik weet dat anderen dit hebben genoemd en je wilt het niet horen, maar gebruik SQL*Loader of externe tabellen. Mijn gemiddelde laadtijd voor tabellen van ongeveer dezelfde breedte is 12,57 seconden voor rijen van iets meer dan 10 meter. Deze hulpprogramma's zijn expliciet ontworpen om gegevens snel in de database te laden en zijn er redelijk goed in. Dit kan wat extra tijdsboetes opleveren, afhankelijk van het formaat van uw invoerbestand, maar er zijn nogal wat opties en ik heb zelden bestanden moeten wijzigen voordat ze werden geladen.

Als u dit niet wilt, hoeft u uw hardware nog niet te upgraden; je moet alle mogelijke belemmeringen om dit snel te laden verwijderen. Om ze op te sommen, verwijdert u:

  1. De index
  2. De trigger
  3. De reeks
  4. De partitie

Met al deze zaken verplicht je de database om meer werk te doen en omdat je dit transactioneel doet, gebruik je de database niet ten volle.

Laad de gegevens in een aparte tabel, zeg ABC_LOAD . Nadat de gegevens volledig zijn geladen, voert u een enkele uit INSERT-instructie in ABC.

insert into abc
select abc_seq.nextval, a.*
  from abc_load a

Wanneer u dit doet (en zelfs als u dit niet doet), zorg er dan voor dat de cachegrootte van de reeks correct is; om te citeren:

Wanneer een toepassing een reeks in de reekscache benadert, worden deze reeksnummers snel gelezen. Als een toepassing echter toegang krijgt tot een reeks die zich niet in de cache bevindt, moet de reeks van schijf naar de cache worden gelezen voordat de reeksnummers worden gebruikt.

Als uw toepassingen veel reeksen tegelijk gebruiken, is uw reekscache mogelijk niet groot genoeg om alle reeksen te bevatten. In dit geval kan toegang tot volgnummers vaak schijflezen vereisen. Voor snelle toegang tot alle reeksen moet u ervoor zorgen dat uw cache voldoende items heeft om alle reeksen die gelijktijdig door uw toepassingen worden gebruikt, te bevatten.

Dit betekent dat als je 10 threads hebt die tegelijkertijd 500 records schrijven met deze reeks, je een cachegrootte van 5.000 nodig hebt. In het document ALTER SEQUENCE staat hoe u dit kunt wijzigen:

alter sequence abc_seq cache 5000

Als je mijn suggestie opvolgt, zou ik de cache vergroten tot iets van ongeveer 10,5 m.

Kijk naar het gebruik van de APPEND hint (zie ook Oracle Base); dit instrueert Oracle om een ​​direct-path insert te gebruiken, die gegevens direct aan het einde van de tabel toevoegt in plaats van te zoeken naar ruimte om het te plaatsen. Je kunt dit niet gebruiken als je tabel indexen heeft, maar je zou het kunnen gebruiken in ABC_LOAD

insert /*+ append */ into ABC (SSM_ID, invocation_id , calc_id, ... )
select 'c','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'a','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'b','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'c','g',NULL, 'test', 123 , 'N', 'asdf' from dual

Als u de APPEND-hint gebruikt; Ik zou TRUNCATE ABC_LOAD . toevoegen nadat je hebt ingevoegd in ABC anders zal deze tafel oneindig groeien. Dit zou veilig moeten zijn, aangezien u dan klaar bent met het gebruik van de tafel.

Je vermeldt niet welke versie of editie of Oracle je gebruikt. Er zijn een aantal extra kleine trucjes die je kunt gebruiken:

  • Oracle 12c

    Deze versie ondersteunt identiteitskolommen; je zou de reeks volledig kunnen verwijderen.

    CREATE TABLE ABC(
       seq_no         NUMBER GENERATED AS IDENTITY (increment by 5000)
    
  • Oracle 11g r2

    Als je de trekker overhoudt; u kunt de reekswaarde direct toewijzen.

    :new.seq_no := ABC_seq.nextval;
    
  • Oracle Enterprise-editie

    Als u Oracle Enterprise gebruikt, kunt u de INSERT versnellen vanuit ABC_LOAD door de PARALLEL hint te gebruiken:

    insert /*+ parallel */ into abc
    select abc_seq.nextval, a.*
      from abc_load a
    

    Dit kan zijn eigen problemen veroorzaken (te veel parallelle processen enz.), dus test. Het misschien hulp voor de kleinere batch-inserts, maar het is minder waarschijnlijk omdat u tijd verliest bij het berekenen van welke thread wat moet verwerken.

tl;dr

Gebruik de hulpprogramma's die bij de database worden geleverd.

Als je ze niet kunt gebruiken, verwijder dan alles wat de invoeging zou kunnen vertragen en doe het in bulk, want daar is de database goed in.



  1. MariaDB JSON_OBJECT() uitgelegd

  2. MySQL vervangen door Percona op Plesk CentOS 7

  3. Fix "ERROR 1136 (21S01):Kolomtelling komt niet overeen met waardetelling op rij 1" bij het invoegen van gegevens in MySQL

  4. @GeneratedValue polymorfe abstracte superklasse over MySQL