Devo passare alle tabelle in memoria e memorizzato proc o NoSql (CosmosDB) [chiuso]

0

Ho molti dati. Oggetti con altri oggetti nidificati come questo (JSON):

{
  id: 12,
  Code: "a code",
  country: "at",
  prices: 
  [{
     { price: 100, from "2017-05-05", to "2017-06-05" },  
     { price: 150, from "2017-05-06", to "2017-06-06" },  
     { price: 200, from "2017-05-07", to "2017-06-07" },  
  }]
}

ecc. Ho circa 60k di questi oggetti principale / genitore. I prezzi sono circa 3 milioni di oggetti.

Situazione attuale

Ho creato un DB SQL di Azure relazionale con tabelle per gli oggetti e una tabella di prezzi con chiave esterna. Lo stesso vale per la tabella dei paesi, ecc. Non ho problemi con i database relazionali. Ho avuto un'istanza S3 di un database SQL di Azure e anche un LocalDB. Entrambi sono non abbastanza veloci . Per inserire o aggiornare, utilizzo la stored procedure. Uno per tavolo. Quindi per archiviare solo 1 oggetto, eseguo un proc memorizzato per scoprirlo, necessita di un inserto o di un aggiornamento e immagazzino l'oggetto principale / principale. Restituisce il (nuovo) ID e lo imposta come chiave esterna per l'oggetto prezzo. Inoltre, memorizza circa 100 oggetti di prezzo e passa a quello successivo. Questo richiede più di un'ora per memorizzare 100 oggetti principale / principale con i relativi prezzi.

Le soluzioni che considero

  1. upscale ad Azure SQL Premium e ridimensiona a S0 (standard) quando ho finito. docs
  2. vai in memoria (che non ha chiavi esterne ...)
  3. passa a NoSQL (cosmos db)

Ho provato la soluzione 3 e ho trovato questo:

Ho fatto una dimostrazione del concetto memorizzando gli oggetti come json in cosmos db (era ancora un documento db allora) ed era veloce. Tuttavia, l'esecuzione di query è stato difficile perché non è possibile eseguire una sottoquery o una media o una somma. link

o dovrei memorizzare le righe dei prezzi come nuovi documenti e avere una "chiave esterna" sull'oggetto principale / principale?

Devo scavare di più nell'opzione 3, o consiglieresti 1 o 2?

Modifica per Ewan I miei stored proc: per oggetto principale / principale:

ALTER PROCEDURE [dbo].[InsertUpdateParent]
(
    @code nvarchar(max),
    @name nvarchar(max),
    @lat float,
    @lng float,
    @country int,
    @countryCode nvarchar(2)
)
AS
BEGIN
DECLARE @id int;
DECLARE @err int;
DECLARE @newObject bit;
    SET NOCOUNT ON

    IF (@country = 0)
    begin
         select @country = id from countries where code = @countrycode;
         SELECT @err = @@error;
    end
    IF EXISTS (SELECT ID FROM ParentObject where code = @code)
    begin
        SELECT @id = ID FROM ParentObject where code = @code;
        SELECT @err = @@error;
        SELECT @newObject = 0;
        UPDATE ParentObject SET 
            [Name] = @name,
            Latitude = @lat,
            Longitude = @lng,
            CountryId = @country
        WHERE code = @code;
        SELECT @err = @@error;
    end
    else
    begin
        SELECT @newObject = 1;
        INSERT INTO [dbo].[ParentObject]
           ([Code]
           ,[Name]
           ,[Latitude]
           ,[Longitude]
           ,[CountryId]
     VALUES
           (@code, @name, @lat, @lng, @country);
            select @id = SCOPE_IDENTITY();
            SELECT @err = @@error;
    end
    IF @err <> 0
        PRINT '@err is ' + ltrim(str(@err)) + '.' 
    else
    return @id;
END

e per i prezzi:

ALTER PROCEDURE [dbo].[InsertUpdatePrices]
(
    @from as datetime,
    @to as datetime,
    @parentId as int,
    @price as decimal(18,2)
)
AS
BEGIN
    declare @id int;
    SET NOCOUNT ON

    IF EXISTS (SELECT ID FROM prices where ArrivalDateFrom = @from and ArrivalDateTo= @to and ParentObjectId = @parentId )
    begin

        SELECT @id = ID FROM prices where ArrivalDateFrom = @from and ArrivalDateTo= @to and ParentObjectId = @parentId;

            UPDATE [dbo].[Prices]
            SET 
                [ArrivalDateFrom] = @from,
                [ArrivalDateTo] = @to,
                [Price] = @price,
                [ParentObjectId] = @parentId
            WHERE ID = @id

    end
    else
    begin

        INSERT INTO [dbo].[Prices]
               ([ArrivalDateFrom]
               ,[ArrivalDateTo]
               ,[Price]
               ,[ParentObjectId])
         VALUES
               (@from
               ,@to
               ,@price
               ,@parentId);
        select @id = SCOPE_IDENTITY();
    end
    return @id;
END
    
posta JP Hellemons 18.07.2017 - 13:56
fonte

2 risposte

1

Ok. Penso che la lentezza sia principalmente un fattore del tuo sql. Quale può essere semplificato.

Per prima cosa, esamina se hai davvero bisogno dell'ID generato dal database piuttosto che di un guid. o nel caso del tuo oggetto genitore il parametro 'code'.

Seconda. Invece di Inserisci o Aggiorna prova a eliminare e inserire. cioè Delete where id=@id; Insert into...

Ciò rimuove le selezioni per verificarne l'esistenza e consente anche un aggiornamento degli oggetti secondari molto più snello. vale a dire

Delete from prices where parentId=@pid

Insert into prices (....)
Insert into prices (....)
Insert into prices (....)

La rimozione dei Selects dal tuo processo preverrà i blocchi delle tabelle e renderà le cose più facili da eseguire in parallelo.

Penso che dovresti vedere un enorme aumento della velocità con questi cambiamenti.

Perderei gli sproc e farei tutto in codice. Gli sproc non aggiungeranno molta velocità e ti impediranno di ottimizzare in base a ciò che già sai. cioè ho cancellato tutti gli oggetti secondari quindi so che è corretto inserirli senza controllo, ecc. Puoi anche scegliere quando apri e chiudi le tue transazioni e, eventualmente, raggruppa più inserti.

Il passaggio a un NoSql db ha lo stesso effetto, in quanto controllerai solo la chiave primaria dell'oggetto padre prima di sovrascriverla.

Tuttavia, la tua struttura relazionale attuale ti consente di selezionare oggetti padre in base agli attributi dei loro figli. cioè prendi i prodotti che costano tra x e oggi.

    
risposta data 18.07.2017 - 15:12
fonte
1

Dipende davvero dai tuoi dati e dalla tua quantità. Un approccio molto comune in questi giorni è avere un approccio ibrido. Il database SQL è l'archivio dei record e quindi qualcosa come ElasticSearch o Solr viene popolato da quei dati. Entrambi utilizzano un indice di Lucene sotto le copertine e in pratica significa che disponi di funzionalità di ricerca molto potenti.

Con NoSQL perdi ACID e devi convivere con BASE ( ref ). Questo è il prezzo che si paga per la capacità di scalare. Se hai bisogno di transazioni ACID, allora ottimizza il tuo SQL.

Dopo aver effettuato la transizione da SQL a NoSQL (ElasticSearch), posso dire per esperienza che mentre ottieni un ordine di grandezza della velocità, perdi la sicurezza delle query SQL. Poiché SQL è uno standard utilizzato da molto tempo, puoi essere relativamente sicuro che il tuo SQL scritto su una vecchia versione di un server continuerà a funzionare su una versione più recente. Non hai quella confidenza con i database NoSQL (ElasticSearch ha avuto grossi cambiamenti dalla versione 1.x alla 2.x che mi ha causato un sacco di rilavorazioni).

Una cosa che può aiutare con gli inserti SQL è usare l'elaborazione batch . Fondamentalmente ciò che fa è disattivare l'indicizzazione riga per riga, e fare tutto in una volta quando si impegna la transazione. Ciò risparmia molto tempo. Sfortunatamente la sintassi per l'elaborazione in batch è leggermente diversa per ogni database SQL.

    
risposta data 18.07.2017 - 15:30
fonte

Leggi altre domande sui tag