LA CAMPANA

C’è chi ha letto questa notizia prima di te.
Iscriviti per ricevere nuovi articoli.
E-mail
Nome
Cognome
Come vuoi leggere La Campana?
Niente spam

Le linee in 1C 8.3 nel linguaggio 1C integrato rappresentano valori tipo primitivo Linea. Valori di questo tipo contenere una stringa Unicode di lunghezza arbitraria. Le variabili di tipo stringa sono un insieme di caratteri racchiusi tra virgolette.

Esempio 1. Creiamo una variabile stringa con testo.

StringVariable = "Ciao mondo!";

Funzioni per lavorare con stringhe in 1s 8.3

IN questa sezione Verranno fornite le principali funzioni che permettono di modificare le righe in 1c, oppure analizzare le informazioni in esse contenute.

StrLength

ForzaLunghezza(<Строка>) . Restituisce il numero di caratteri contenuti nella stringa passata come parametro.

Esempio 2. Contiamo il numero di caratteri nella riga "Hello world!"

String = "Ciao mondo!"; NumerodiCaratteri = StrLength(Stringa); Rapporto(NumeroCaratteri);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione del numero di caratteri nella riga: 11.

AbbrL

AbbrL(<Строка>) . Taglia i caratteri non importanti a sinistra del primo simbolo significativo in linea.
Personaggi minori:

  • spazio;
  • spazio unificatore;
  • tabulazione;
  • ritorno a capo;
  • avanzamento riga;
  • traduzione del modulo (pagina).

Esempio 3. Rimuovi tutti gli spazi dal lato sinistro della riga "world!" e aggiungi la riga "Ciao".

String = Abbreviazione("mondo!"); Stringa = "Ciao"+Stringa; Rapporto(Stringa);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione della riga "Hello world!" sullo schermo.

Abbreviato

Abbr(<Строка>) . Taglia i caratteri non significativi a destra del primo carattere significativo nella stringa.

Esempio 4. Forma dalle righe "Ciao" e "pace!" la frase "Ciao mondo!"

Linea = Abbreviazione("Ciao ")+" "+ Abbreviazione("mondo!"); Rapporto(Stringa);

AbbrLP

AbbrLP(<Строка>) . Taglia i caratteri non significativi a destra del primo carattere significativo nella stringa e taglia anche i caratteri non significativi a sinistra del primo carattere significativo nella stringa. Questa funzione viene utilizzato più spesso dei due precedenti, poiché è più universale.

Esempio 5. Rimuovere i caratteri non significativi a sinistra e a destra nel nome della controparte.

Controparte = Directory.Controparti.Trova per dettagli("TIN", "0777121211"); AccountObject = Account.GetObject(); ControparteOggetto.Nome = AbbrLP(ControparteOggetto.Nome); AccountObject.Write();

Leone

Leone(<Строка>, <ЧислоСимволов>) . Ottiene i primi caratteri della stringa, il numero di caratteri è specificato nel parametro Numero di caratteri.

Esempio 6. Lascia entrare la struttura Dipendente contenere il nome, il cognome e il patronimico del dipendente. Ottieni una stringa con cognome e iniziali.

NomeIniziale = Lev(Dipendente.Nome, 1); Iniziale Patronimico = Leone(Dipendente. Patronimico, 1); NomeCompleto = Dipendente.Cognome + " " + Nome Iniziale + "."

+ Iniziale centrale + ".";

Giusto<Строка>, <ЧислоСимволов>) Giusto( Numero di caratteri.. Ottiene gli ultimi caratteri di una stringa, il numero di caratteri specificati nel parametro

Se il numero di caratteri specificato supera la lunghezza della stringa, viene restituita l'intera stringa. Esempio 7. Lascia che una data nel formato "aaaammgg" venga scritta alla fine di una variabile stringa, ottieni una stringa con la data e convertila nel tipo.

Data Stringa = " Data attuale

: 20170910"; StringDate = Diritti(String, 8); Date = Date(StringDate);

Mercoledì<Строка>, <НачальныйНомер>, <ЧислоСимволов>) Mercoledì( Linea. Ottiene una sottostringa dalla stringa passata come parametro , a partire dal carattere il cui numero è specificato nel parametro NumeroIniziale Numero di caratteri. e la lunghezza passata nel parametro , a partire dal carattere il cui numero è specificato nel parametro La numerazione dei caratteri in una riga inizia da 1. Se nel parametro viene specificato un valore minore o uguale a zero, il parametro assume il valore 1. Se il parametro Numero di caratteri

non è specificato, vengono selezionati i caratteri fino alla fine della riga.

Esempio 8. Lascia che la variabile stringa che inizia dalla nona posizione contenga il codice regionale, dovresti ottenerlo e scriverlo in una riga separata.

String = "Regione: 99 Mosca"; Regione = Avg(Stringa, 9, 2);

Pagina Trova<Строка>, <ПодстрокаПоиска>, <НаправлениеПоиска>, <НачальнаяПозиция>, <НомерВхождения>) StrFind(

  • Linea. Cerca una sottostringa specificata in una stringa, restituendo il numero di posizione del primo carattere della sottostringa trovata. Diamo un'occhiata ai parametri di questa funzione:
  • . Stringa di origine; Cerca sottostringa
  • . Cerca sottostringa; Direzione della ricerca
    • . Specifica la direzione in cui cercare una sottostringa in una stringa. Può assumere valori:;
    • Direzione della ricerca. Dall'inizio;
  • Direzione ricerca.Fine Posizione iniziale
  • . Specifica la posizione nella stringa in cui inizia la ricerca; NumeroOccorrenze

. Specifica il numero di occorrenze della sottostringa cercata nella stringa di origine.

Esempio 9. Nella riga "Hello world!" Determina la posizione dell'ultima occorrenza del carattere "e".

PositionNumber = StrFind("Ciao mondo!", "e", SearchDirection.End); Rapporto(NumeroPosizione);

Il risultato dell'esecuzione di questo codice sarà quello di visualizzare il numero dell'ultima occorrenza del simbolo "e": 9.

VReg<Строка>) VReg(

Esempio 10: Converti la stringa "ciao mondo!" al maiuscolo.

StringVreg = VReg("ciao mondo!"); Rapporto(StringVreg);

Il risultato dell’esecuzione di questo codice sarà la visualizzazione della riga “HELLO WORLD!”

NReg

NReg(<Строка>) . Converte tutti i caratteri nella stringa specificata in 1s8 in minuscolo.

Esempio 11: Converti la stringa "HELLO WORLD!" in minuscolo.

StringNreg = NReg("CIAO MONDO!"); Rapporto(StringVreg);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione della riga "ciao mondo!"

Tregg

TReg(<Строка>) . Converte una stringa come segue: viene convertito il primo carattere di ogni parola maiuscolo, i restanti caratteri della parola vengono convertiti in minuscolo.

Esempio 12: Scrivi in ​​maiuscolo le prime lettere delle parole nella riga "ciao mondo!"

StringTreg = TReg("ciao mondo!"); Rapporto(StringTreg);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione della riga "Hello World!"

Simbolo

Simbolo(<КодСимвола>) . Ottiene un carattere tramite il relativo codice Unicod.

Esempio 13. Aggiungi sinistra e destra alla riga "Hello World!" simbolo ★

StringWithStars = Simbolo("9733")+"Ciao Mondo!"+Simbolo("9733"); Rapporto(StringWithStars);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione della riga “★Hello World!★”

Codice simbolo

CodiceSimbolo(<Строка>, <НомерСимвола>) . Ottiene il codice del carattere Unicode dalla stringa specificata nel primo parametro, situata nella posizione specificata nel secondo parametro.

Esempio 14. Scopri il codice dell'ultimo carattere nella riga "Hello World!"

String = "Ciao mondo!"; CodiceCarattere = CodiceCarattere(Stringa, StrLength(Stringa)); Notifica(CodiceCarattere);

Il risultato dell’esecuzione di questo codice sarà la visualizzazione del codice simbolo “!” - 33.

Stringavuota

StringaVuota(<Строка>) . Controlla se la stringa è composta solo da caratteri non significativi, ovvero se è vuota.

Esempio 15. Controlla se una stringa composta da tre spazi è vuota.

Vuoto = StringaVuota(" "); Rapporto(Vuoto);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione della parola "Sì" (un'espressione stringa di un valore logico VERO).

PaginaSostituisci

StrSostituisci(<Строка>, <ПодстрокаПоиска>, <ПодстрокаЗамены>) . Trova tutte le occorrenze della sottostringa di ricerca nella stringa di origine e la sostituisce con la sottostringa di sostituzione.

Esempio 16. Nella riga "Hello World!" sostituire la parola “Pace” con la parola “Amici”.

String = StrReplace("Ciao mondo!", "Mondo", "Amici"); Rapporto(Stringa);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione della riga "Ciao amici!"

StrNumeroLinee

StrNumeroRiga(<Строка>) . Consente di contare il numero di righe in una stringa multilinea. Per andare a nuova linea in 1s 8 viene utilizzato il simbolo PS(carattere di nuova riga).

Esempio 17. Determinare il numero di righe nel testo:
"Prima riga
Seconda riga
Terza riga"

Numero = StrNumeroString("Prima riga"+Caratteri.PS +"Seconda riga"+Simboli.PS +"Terza riga"); Rapporto(Numero);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione del numero di righe del testo: 3

StrGetString

StrGetString(<Строка>, <НомерСтроки>) . Ottiene una riga in una stringa su più righe in base al relativo numero. La numerazione delle righe inizia da 1.

Esempio 18. Ottieni l'ultima riga del testo:
"Prima riga
Seconda riga
Terza riga"

Testo = "Prima riga" + Simboli PS + "Seconda riga" + Simboli PS + "Terza riga"; LastRow = StrGetRow(Testo, StrNumberLines(Testo)); Report(UltimaRiga);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione della riga “Terza riga”.

PageNumberOccorrenze

StrNumberOccorrenze(<Строка>, <ПодстрокаПоиска>) . Restituisce il numero di occorrenze della sottostringa specificata in una stringa. La funzione distingue tra maiuscole e minuscole.

Esempio 19. Determina quante volte la lettera "c" appare nella riga "Righe in 1s 8.3 e 8.2", indipendentemente dal caso.

Linea = "Linee in 1s 8.3 e 8.2"; NumberOccurrences = StrNumberOccurrences(Vreg(String), "With"); Rapporto(Numerooccorrenze);

Il risultato dell'esecuzione di questo codice sarà la visualizzazione del numero di occorrenze: 2.

La pagina inizia con

StrIniziaCon(<Строка>, <СтрокаПоиска>) . Controlla se la stringa passata nel primo parametro inizia con la stringa nel secondo parametro.

Esempio 20. Determinare se il TIN della controparte selezionata inizia con il numero 1. Inserire la variabile Controparte Controparti.

TIN = Controparte.TIN; StartsUNits = StrStartsWith(TIN, "1"); Se inizia con le unità Then //Il tuo codice EndIf;

FinepaginaOn

StrEndsWith(<Строка>, <СтрокаПоиска>) . Controlla se la stringa passata nel primo parametro termina con la stringa nel secondo parametro.

Esempio 21. Determinare se il TIN della controparte selezionata termina con il numero 2. Inserire la variabile Controparte viene memorizzato un riferimento a un elemento della directory Controparti.

TIN = Controparte.TIN; TerminaConDue = StrFineCon(TIN, "2"); If EndsInTwo Then //Il tuo codice EndIf;

Pagina divisa

StrDivide(<Строка>, <Разделитель>, <ВключатьПустые>) . Divide una stringa in parti utilizzando i caratteri delimitatori specificati e scrive le stringhe risultanti in una matrice. Il primo parametro memorizza la stringa sorgente, il secondo contiene la stringa contenente il delimitatore e il terzo indica se le stringhe vuote devono essere scritte nell'array (per impostazione predefinita VERO).

Esempio 22. Prendiamo una stringa contenente numeri separati dal simbolo “;”, otteniamo un array di numeri dalla stringa.

Stringa = "1; 2; 3"; Array = StrDivide(Stringa, ";"); Per Count = 0 Per Array.Quantity() - 1 tentativo di ciclo Array[Count] = Number(AbbrLP(Array[Count]));

Matrice di eccezioni[Sch] = 0;

PaginaConnetti

StrConnect(<Строки>, <Разделитель>) . Converte la matrice di stringhe dal primo parametro in una stringa contenente tutti gli elementi della matrice separati dal delimitatore specificato nel secondo parametro.

Esempio 23. Utilizzando l'array di numeri dell'esempio precedente, ottieni la stringa originale.

Per Account = 0 Per Array.Quantity() - 1 Ciclo Array[Act] = String(Array[Act]); FineCiclo; Riga = StrConnect(Array, "; ");

Mi chiamo Pavel Barketov, lavoro presso l'azienda Softpoint. Risolviamo problemi di ottimizzazione delle prestazioni da oltre 10 anni. E nonostante gran numero problemi risolti, il loro numero non diminuisce, ma cresce in modo esponenziale. I volumi di dati stanno aumentando e i compiti di ottimizzazione del lavoro con questi dati stanno diventando più complessi. Questo processo è inevitabile.

Argomento dell'articolo - approcci non banali all’ottimizzazione. Verrà preso in considerazione due aspetti:

  • Primo - ricerca per sottostringa. Gli utenti lo utilizzano frequentemente e molti probabilmente hanno già riscontrato attese significative che le ricerche delle sottostringhe non sono abbastanza veloci;
  • Secondo - contenere documenti di grandi dimensioni, come chiusura mensile, calcolo dei costi. Sicuramente molti hanno riscontrato il fatto che i contabili eseguono questi documenti per 5-9 ore, di notte e fuori orario. La cosa più interessante è che i metodi di ottimizzazione classici non sempre aiutano in questo caso. Se esegui una misurazione delle prestazioni nel debugger mentre conduci tali documenti, vedrai che la maggior parte del tempo viene spesa scrivendo su strutture temporanee o reali: tabelle, registri, ecc. E questo problema non può essere risolto usando i metodi classici.

Cerca per sottostringa

Il primo argomento è la ricerca di sottostringhe. Nel corso di quest'anno ho riscontrato più volte problemi con questa operazione. Vieni a compagnia assicurativa per rinnovare la polizza si offrono di trovarti tramite numero di telefono. È chiaro che non si tratta di una classica ricerca per numero di telefono completo, perché l'utente potrebbe inserire il numero con un otto, un sette o qualcos'altro, quindi effettuerà la ricerca per frammenti del numero. In questo caso vengono utilizzate operazioni di ricerca a lungo termine: in alcune situazioni il ritardo può essere di diversi secondi o arrivare fino a minuti.

Cerca per caratteri iniziali

Inizierò con il primo esempio, quando la ricerca viene effettuata utilizzando i caratteri iniziali. Questo è un caso speciale di ricerca di sottostringhe, quando l'utente sa per certo che il valore cercato inizia con determinati caratteri.

La ricerca per carattere iniziale è implementata in 1C utilizzando il comando SIMILAR(o in inglese, LIKE) indicando il valore con un “%” alla fine (“%” indica una sequenza di eventuali altri caratteri). Ad esempio, stiamo cercando:

Nome SIMILE a "Ivano%"

Tieni presente che se hai un indice su questo campo nel tuo sistema, allora la query SQL utilizzerà Index Seek per questa ricerca- Questa è una ricerca per indice.

Condizione “MI PIACE barra di ricerca» equivale a cercare un intervallo di valori. Nel caso particolare, quando cerchiamo "ivano%" ciò equivale a cercare nell'intervallo di cognomi che iniziano con "ivano" e finiscono con "ivanp" (perché il carattere "p" viene dopo il carattere "o" ).

Gli ottimizzatori moderni convertono in modo indipendente una query LIKE in una query di ricerca per intervallo. Pertanto, se nel tuo sistema è presente un indice su questo campo, quando interpreti la query in termini SQL, otterrai esattamente questo risultato: l'ottimizzatore presenterà la query con LIKE come ricerca di intervallo.

Pertanto, è possibile eseguire il classico ricerca rapida utilizzando l'indice (Ricerca indice). Non ci sono problemi con questo o possono essere risolti in modo semplice.

Cerca per occorrenza

Ora prendiamo un esempio più complicato, quando non si sa esattamente dove si trova il valore desiderato nella riga e viene implementata una ricerca in base alla presenza della riga. In questo caso, nella query “MI PIACE”, “%” appare su entrambi i lati.

Quando convertiamo una query di questo tipo in SQL, vediamo che cambia solo il comando (due “%” sono già utilizzati nel valore).

Diamo uno sguardo più da vicino al piano di esecuzione. Qui vediamo lo stesso Index Seek, ma in questo caso non funziona in modo efficace.

Il fatto è che l'indice per nome della directory che stiamo considerando è composto da diversi campi.

  • Il primo di questi è il separatore contabile.
  • Poi c'è il campo di ricerca.

E quindi quando il piano di esecuzione mostra "Index Seek" significa questo la ricerca viene effettuata utilizzando il primo campo del separatore- nella diapositiva sopra puoi vederlo la ricerca del nostro valore di ricerca Desc è completamente inutilizzabile.

Cosa fare in questa situazione? Nella mia pratica, molto spesso agli utenti veniva vietato di utilizzare le richieste di iscrizione. E in alcuni casi, gli utenti stessi non hanno utilizzato questa funzionalità, perché il tempo di esecuzione era molto significativo, ma dovevano continuare a lavorare. Pertanto, dovevano uscire in altri modi: sceglievano dagli elenchi, cercavano di trovare i primi caratteri e così via.

Ma questo porta all’insoddisfazione per la funzionalità e alla percezione errata del sistema. L'utente capisce che il sistema non può far fronte a qualcosa e non funziona come previsto. Questo è sbagliato.

Un approccio non banale per risolvere il problema della ricerca per sottostringa

Diamo ora un'occhiata approccio non banale per risolvere questo problema.

Designiamo una serie di tolleranze:

  • Il primo è perché moderno i dischi hanno dimensioni illimitate, diciamo che hai molto spazio su disco che puoi utilizzare.
  • Secondo - l'utente cerca non per uno o due caratteri, ma per qualche frammento. Ad esempio, nessuno di noi cerca "al": questa è troppo poca selettività. Stanno cercando una sequenza significativa di personaggi. Qui abbiamo scelto come esempio una ricerca a sei caratteri.

Nel modulo è stato scritto un esempio della stringa richiesta "Alexa" e lo testeremo con il suo aiuto.

  • Diciamo che abbiamo un campo con il cognome, nome e patronimico del cliente. Il primo passo è scomporre automaticamente questo valore in frammenti di sei caratteri con uno spostamento di “1” e otteniamo una serie di frammenti (vedi sopra), che allo stesso tempo appartengono sempre al valore desiderato. Abbiamo ricevuto frammenti che teoricamente l'utente potrebbe inserire. Vale a dire, nell'ultima diapositiva abbiamo stabilito che stiamo cercando sei personaggi. Possono essercene cinque o quattro, solo la dimensione della struttura sarà maggiore.

  • Nel secondo passaggio noi scriviamo questi insiemi in una struttura separata(potrebbe essere una tabella, un registro di informazioni, ecc.) e otteniamo una selezione in cui frammento specifico appartiene a significati diversi.

  • E nel terzo passaggio, durante la ricerca per sottostringa nella struttura della query 1C, aggiungiamo "MI PIACE". condizione aggiuntiva"E", che filtra il numero di combinazioni possibili, e da questa struttura aggiuntiva (potrebbe essere un registro di informazioni) estraiamo tutti gli elementi che possiedono i frammenti di stringa richiesti.

Ad esempio, un utente sta cercando un cliente con il cognome "Soldatov". Si tratta di otto caratteri, il che significa che ci saranno tre frammenti di sei caratteri di lunghezza che stiamo cercando nella struttura del servizio. Successivamente, combiniamo tutto questo in una richiesta. Pertanto, si ottiene un'ulteriore filtrazione.

Di conseguenza, ci liberiamo del segno "%" (ovvero, davanti a questi frammenti ci sarà sempre il simbolo di cui abbiamo bisogno) e durante l'esecuzione della query interna verrà utilizzato Index Seek, per il quale abbiamo lottato.

In pratica, si scopre una storia molto interessante: accelerazione decine, centinaia di volte. Inoltre, tutto ciò può essere fatto utilizzando 1C, il che è molto carino. Non è necessario riscrivere la logica; l'utente sarà contento che la sua query di ricerca sia stata velocizzata. Nell'esempio, l'accelerazione va da 4 secondi a 0,05 secondi e se la nostra richiesta avesse inizialmente impiegato due minuti per essere completata, sarebbe stata eseguita in meno di un secondo.

Il meccanismo che ti ho mostrato non è una sorta di esempio sperimentale, funziona già per clienti reali.

Attività preparatorie all'implementazione

Ora parlerò brevemente delle attività preparatorie.

  • All'inizio il registro deve essere completato valori iniziali . Per fare questo, dobbiamo pianificare una finestra normativa.
  • Successivamente, dobbiamo mantenere la coerenza dei dati: questo significa ci deve essere un abbonamento per modificare il valore in modo che questi frammenti vengano ricostruiti automaticamente.
  • E l'ultima cosa - aggiungere un modulo di ricerca standard.

La compilazione del registro può essere eseguita sia utilizzando gli strumenti 1C che utilizzando SQL.

Posso dire che la compilazione di una struttura del genere per 17 milioni di valori richiede circa 20-25 minuti. Naturalmente gli utenti non dovrebbero modificare i valori della directory in questo momento.

Se calcoliamo per un milione di valori circa 100 caratteri da 6 in un frammento, otteniamo circa 4,7 GB. Devi pianificare per avere questo posto. Se nella tua directory sono presenti, ad esempio, 100 milioni di valori, devi pianificare lo spazio che sarà disponibile su disco.

La necessità di tenere conto delle statistiche sulla popolarità dei frammenti

Questo metodo funzionerà sempre rapidamente?

Questo è influenzato da statistiche sulla popolarità dei frammenti.

  • Ad esempio, hai un frammento "alekse", che può essere incluso nel nome Alexey, nel patronimico Alekseevich, nel cognome Alekseenko, ecc. Questo frammento può essere compreso in 50-100mila registrazioni.
  • E ci sono frammenti usati raramente.

Pertanto, vengono visualizzate le statistiche sulla popolarità dei frammenti.

notare che se la popolarità dei frammenti è bassa (100 elementi), otteniamo un aumento di velocità di 0,1 secondi.

Se la sottostringa è abbastanza popolare (50mila elementi), otteniamo un degrado e molto maggiore che se non ci fosse stata l'ottimizzazione.

Così, è necessario creare uno schema di esecuzione delle query migliorato, in cui otterremmo prima il valore di popolarità della sottoquery. Questo viene fatto in tre o cinque righe in 1C. Allo stesso tempo, sappiamo per certo che se una linea è impopolare, allora va lungo il primo ramo, e se è popolare, allora va lungo il secondo.

Come funziona l'accelerazione? C'è una richiesta di ricerca dal modulo, quindi accediamo al registro delle informazioni con le statistiche, otteniamo l'elemento e poi scegliamo cosa utilizzare: una richiesta classica o accelerata.

Ora diamo un'occhiata a come viene eseguita una query SQL su un server SQL.

La diapositiva mostra un diagramma semplificato:

  • c'è una richiesta all'ottimizzatore;
  • esaminiamo le statistiche sui campi utilizzati nella richiesta;
  • scegliamo quale piano di esecuzione utilizzare, ovvero scegliamo una strategia di esecuzione delle query (ad esempio, un ciclo annidato).

Come si presenta lo schema che abbiamo implementato?

  • Abbiamo fatto il nostro indice. Non indice standard SQL, non l'indice 1C, ma il proprio indice, necessario per risolvere questo problema;
  • Inoltre, ci siamo trovati di fronte al fatto che avevamo bisogno del nostro statistiche;
  • E tu hai bisogno del tuo ottimizzatore, che, sulla base di queste statistiche, decide quale filiale scegliere.

Sulla base di questa logica, possiamo dire che questo processo rivela il significato del motivo per cui abbiamo bisogno di indici, statistiche e di un ottimizzatore.

Per coloro che non sapevano perché è necessario mantenere le statistiche in SQL, dai un'occhiata a questa logica e capirai che se è errata o irrilevante, seguiremo il ramo sbagliato. La richiesta rallenterà. Comprendiamo perché è necessario mantenere le statistiche in modo efficiente e corretto: ciò influisce sulle prestazioni e sull'indice.

Se non è presente alcun indice, eseguiremo la scansione di tutti i valori.

Pertanto, abbiamo creato almeno un primitivo, ma il nostro ottimizzatore. Possiamo dire di aver sentito “sulle nostre dita” come MS SQL e altri DBMS lo fanno e creando le nostre strutture.

Velocizzare documenti di grandi dimensioni

Vorrei passare al secondo argomento: velocizzare i documenti di grandi dimensioni.

Nelle attività di produzione, ci imbattiamo spesso in alcune procedure normative, quali: chiusura mensile, rapporto all'agente, calcolo dei costi. Questi documenti pesanti e voluminosi richiedono molto tempo per essere elaborati e completati. E quando esaminiamo il debugger e tracciamo queste operazioni, lo vediamo 1C inserisce i valori riga per riga in qualche tabella e questo occupa la maggior parte del tempo. E non si può fare nulla al riguardo. L'unica raccomandazione che si può offrire è quella di velocizzare il disco (l'efficacia di questa soluzione è molto dubbia e richiede un'analisi preliminare).

Propongo di tornare indietro nella storia e considerare come ciò è stato fatto nel 1C, a partire da 8.0 a 8.3 - questo è stato fatto riga per riga. Ogni volta che il server SQL analizzava la richiesta, la elaborava, creava un piano di esecuzione, lo aggiungeva, inviava un comando a 1C sul successo e riceveva la richiesta successiva. E queste richieste sono passate passo dopo passo dal server delle applicazioni 1C a MS SQL.

È chiaro che se nel documento sono presenti 40 record, non dovrebbero esserci problemi. Se disponi di 10mila o più record (ci sono organizzazioni con un milione di record nei loro documenti normativi), questo processo richiede molto tempo. Un record viene elaborato molto rapidamente, ma nel documento sono presenti troppi record. Dove vanno le spese generali? Per la rete, per l'esecuzione della richiesta, per il segnale di ritorno, per l'elaborazione di questo segnale nel sistema 1C - in totale, la somma di quattro fasi. Tutte le fasi vengono riassunte, moltiplicate per un milione di righe, e si ottengono le nostre lunghe attese. È chiaro che questo non è terribile.

In 1C, a partire dalla 8.3, sono stati apportati miglioramenti. Ora la query per l'inserimento in tabelle temporanee e registri di informazioni viene preparata sul server SQL e la sua ulteriore esecuzione avviene utilizzando le classiche chiamate RPC, dove Lo stesso provider di accesso 1C (nativo o OLE DB) raggruppa i record e li inserisce in N righe (solitamente 100 righe).

In questo modo si ottiene un'accelerazione dal 30% al 300%. Ma questo non basta ancora, perché oggi hai 10mila righe, domani 20mila righe. Questa non è una soluzione fondamentale al problema; la incontrerai comunque, ma solo tra sei mesi/anno.

Quale maggior parte inserimento rapido a un server SQL o addirittura a qualsiasi DBMS?

Questo INSERTO ALL'INGROSSO. In 1C viene utilizzato BULK INSERT, ma per altri compiti. Vorrei anche velocizzare il lavoro con documenti "di grandi dimensioni" ampliando gli INSERT e aggiungendo record in un unico array al database del server SQL.

Vediamo quale effetto si ottiene. Nell'esempio in esame, abbiamo ottenuto l'accelerazione è di circa 5 volte, ma può essere accelerata di 10 volte. In teoria, il problema principale per accelerare significativamente di più è la velocità del disco. Il disco potrebbe essere il collo di bottiglia.

Anche è importante ricordare un criterio come gli indici. Se inseriscessimo un BULK INSERT in una tabella senza aggiornare gli indici, otterremmo un notevole aumento di velocità (risultato in meno di un secondo). Qui otteniamo 69 secondi perché ogni inserimento nella tabella richiede un indice REFRESH.

In ogni caso, questo metodo consente di ottenere un effetto di 5-10 volte.

Inoltre, qui non vengono prese in considerazione possibilità come il partizionamento e il partizionamento. La situazione potrebbe essere migliorata se sapessimo che BULK INSERT è inserito nel periodo corrente e sposteremmo il periodo irrilevante in un'altra partizione. Ciò avrebbe un effetto ancora maggiore. Si scopre che l'accelerazione è molto buona.

Le possibilità di ottimizzazione sono infinite

Così, le possibilità di ottimizzazione sono infinite. L'unica cosa è non lasciarsi trasportare. Prima dell'ottimizzazione è sempre opportuno calcolare se l'effetto atteso si verificherà o meno. Consiglierei anche in alcune situazioni di “risollevarsi” dal problema, di utilizzare metodi di ottimizzazione delle query non classici, ma completamente diversi che possono portare risultati più significativi.

****************

Questo articolo è stato scritto sulla base dei risultati di un rapporto () presentato al convegno INFOSTART EVENT 2017 COMMUNITY.

Esistono pochi meccanismi per lavorare con le stringhe nelle query 1C. Innanzitutto è possibile aggiungere le linee. In secondo luogo, puoi prendere una sottostringa da una stringa. In terzo luogo, è possibile confrontare le stringhe, anche in base al modello. Questo è probabilmente tutto ciò che si può fare con le stringhe.

Aggiunta di stringhe

Per aggiungere righe in una query, viene utilizzata l'operazione "+". Puoi aggiungere solo stringhe di lunghezza limitata.

SELEZIONARE "Nome: " + Nome Controparti AS Colonna 1 FROM Directory AS Controparti WHERE Controparti

Funzione di sottostringa

SOTTOSTRINGA(<Строка>, <НачальнаяПозиция>, <Длина>)

Analogo della funzione Avg() da modello di oggetto. La funzione Substring() può essere applicata ai dati stringa e consente di selezionare un frammento <Строки> , iniziando con il numero del carattere <НачальнаяПозиция> (i caratteri di una riga sono numerati a partire da 1) e la lunghezza <Длина> caratteri. Il risultato del calcolo della funzione è di tipo stringa a lunghezza variabile e la lunghezza sarà considerata illimitata se <Строка> ha lunghezza e parametri illimitati <Длина> non è una costante o è maggiore di 1024.

Se la lunghezza della stringa è inferiore a quella specificata nel secondo parametro, la funzione restituirà una stringa vuota.

Attenzione! Non è consigliabile utilizzare la funzione SUBSTRING() per convertire stringhe di lunghezza illimitata in stringhe di lunghezza limitata. È invece preferibile utilizzare l'operatore cast EXPRESS().

Funzione simile

Se dobbiamo assicurarci che un attributo stringa soddisfi determinati criteri, lo confrontiamo:

SELECT Controparti Nome AS Colonna 1 FROM Directory Controparti AS WHERE Nome controparti = "Gazprom".

Ma cosa succede se hai bisogno di un confronto più sottile? Non solo uguaglianza o disuguaglianza, ma somiglianza con un certo modello? Questo è esattamente lo scopo per cui è stata creata la funzione SIMILI.

LIKE — Operatore per verificare la somiglianza di una stringa con un modello. Analogo di LIKE in SQL.

L'operatore SIMILAR consente di confrontare il valore dell'espressione specificata a sinistra con la stringa del modello specificata a destra. Il valore dell'espressione deve essere di tipo stringa. Se il valore dell'espressione corrisponde al modello, il risultato dell'operatore sarà TRUE, altrimenti sarà FALSE.

I seguenti caratteri nella stringa del modello sono caratteri di servizio e hanno un significato diverso dal carattere della stringa:

  • % (percentuale): una sequenza contenente un numero qualsiasi di caratteri arbitrari;
  • _ (trattino basso): un carattere arbitrario;
  • […] (v parentesi quadre uno o più caratteri): qualsiasi singolo carattere elencato tra parentesi quadre. L'enumerazione può contenere intervalli, ad esempio a-z, ovvero un carattere arbitrario incluso nell'intervallo, comprese le estremità dell'intervallo;
  • [^...] (tra parentesi quadre un segno di negazione seguito da uno o più caratteri): qualsiasi singolo carattere diverso da quelli elencati dopo il segno di negazione.

Qualsiasi altro simbolo significa se stesso e non comporta alcun carico aggiuntivo. Se uno dei caratteri elencati deve essere scritto come se stesso, deve essere preceduto da<Спецсимвол>. Me stessa<Спецсимвол>(qualsiasi simbolo adatto) è definito nella stessa istruzione dopo parola chiave SIMBOLO SPECIALE.

Casa Appunti da Attraverso lo specchio

07/02/2013 Ricerca per stringa

Implementato nella versione 8.3.3.641.

Abbiamo seriamente migliorato l'input della linea. Per fare ciò, abbiamo dovuto implementare un nuovo potente meccanismo di ricerca nel campo di input. Ora può analizzare rapidamente i milioni di record contenuti nel database.

Abbiamo analizzato le attività di ricerca incontrate dagli utenti. Abbiamo condotto un “audit” dei meccanismi disponibili nella piattaforma che utilizzano vari algoritmi di ricerca. Di conseguenza, l'input di linea ha acquisito funzionalità completamente nuove.

Ora gli utenti possono cercare ovunque nel titolo, non solo all'inizio della riga. Possono utilizzare la ricerca full-text e persino eseguire ricerche utilizzando un processo in background. Per garantire che la ricerca full-text funzioni in modo efficace per l'input riga per riga, abbiamo ulteriormente ottimizzato il motore di ricerca e migliorato le sue prestazioni.

Abbiamo raccolto tutte le nuove proprietà che permettono di personalizzare l'input per riga in una scheda separata della finestra di modifica dell'oggetto di configurazione:

Ad esempio, puoi specificare che la ricerca verrà eseguita in qualsiasi punto della stringa, non solo all'inizio:

Quindi l'utente può digitare qualsiasi frammento di parole e non solo i caratteri con cui inizia la stringa cercata:

L'uso della ricerca full-text quando si inserisce una riga è abilitato da una proprietà separata:

Utilizzando la ricerca full-text, gli utenti possono trovare rapidamente dati rilevanti tra grandi volumi di dati utilizzando una qualsiasi delle parole contenute, ad esempio, nel nome:

Possono anche effettuare ricerche utilizzando diverse parole conosciute. Le parole non finite verranno automaticamente completate con le possibili combinazioni:

Se la quantità di dati è elevata, in entrambi i casi è possibile specificare che la ricerca venga eseguita utilizzando un processo in background:

Quindi, accanto al campo di input, verrà visualizzata per gli utenti un'immagine animata, simile all'immagine che viene visualizzata quando il report viene eseguito in background:

  • se non si prevede che l'oggetto utilizzato nel campo di input contenga una grande quantità di dati, si consiglia di abilitare la ricerca di stringhe ovunque;
  • se in un oggetto è prevista una grande quantità di dati, allora:
    • Ti consigliamo di abilitare la ricerca nel testo completo e in background;
    • allo stesso tempo è possibile utilizzare anche la ricerca per stringa ovunque, ma in combinazione con la ricerca in background e preferibilmente con la ricerca full-text; in modo che la maggior parte delle ricerche venga eseguita tramite la ricerca full-text.

Se necessario è possibile ridefinire tutte le proprietà elencate durante l'esecuzione della soluzione applicativa.

Sul client: nei gestori eventi del campo di input del client Selezione automatica E EndInputText :

Sul server - nel modulo di gestione dell'oggetto di cui si stanno cercando i dati. Nel gestore eventi ElaborazioneReceiveSelectionData :

Naturalmente, in questa posizione, sul server, non è possibile modificare il modo in cui viene eseguita la ricerca "Direttamente" O "Lavoro in background" . Perché l'esecuzione del codice è già stata trasferita al server.

LA CAMPANA

C’è chi ha letto questa notizia prima di te.
Iscriviti per ricevere nuovi articoli.
E-mail
Nome
Cognome
Come vuoi leggere La Campana?
Niente spam