Newsgroup: it.comp.appl.access
Titolo: Errore out of memory su aggiornamento tabella

Ciao a tutti,
Ho un progetto adp (Access xp) per l'estrazione di N record in base a dei
criteri variabili. La tabella in questione contiene circa 17 milioni di
record.
La funzione apre in lettura la tabella ed ad ogni nStep marca il record come
selezionato. Quando il numero dei record marcati è uguale al numero dei
record da estrarre (Me!nNominativi) il ciclo si interrompe. Il problema si
verifica quando devo selezionare i record analizzando tutta la tabella,
arrivato ad un certo punto mi visualizza il messaggio: Out of memory. Dove
sbaglio?
Grazie comunque.
Questo è il codice
    Dim rst As New ADODB.Recordset
    Dim strSQL, strSQLWHERE As String
    Dim SQLWHEREArea, SQLWHERERegione, SQLWHEREProvincia, SQLWHEREComune, x
As String
    Dim zArea, zRegione, zProvincia, zComune, i As Integer
    Dim nNomiDaEstrarre, nStep, nRecord As Double
    ...............
    nStep = Me!NMaxArchivioFiltrati \ Me!nNominativi        'operatore \
divide restituendo solo intero
    If nStep < 1 Then nStep = 1
    i = 1
    nNomiDaEstrarre = 0
    If SQLWHEREArea = "" And SQLWHERERegione = "" And SQLWHEREProvincia = ""
And SQLWHEREComune = "" Then
        strSQL = "SELECT * FROM TPrivati WHERE (Selezionato IS NULL)"
'Analizza tutta la tabella
    Else
        strSQL = "SELECT * FROM TPrivati WHERE (Selezionato IS NULL) AND " &
strSQLWHERE        'con il filtro funziona
    End If
    rst.Open strSQL, CurrentProject.Connection, adOpenForwardOnly,
adLockReadOnly
    If RecordsetisEmpty(rst) = 0 Then
        rst.MoveFirst
        Do While Not rst.EOF
            If i = nStep Then
                DoCmd.RunSQL "EXEC StP_CampoSelezione_Aggiorna " & rst!Id &
", " & Me!chrSelezione
                i = 1
                nNomiDaEstrarre = nNomiDaEstrarre + 1
                If nNomiDaEstrarre = Me!nNominativi Then Exit Do
            End If
            rst.MoveNext                                 'qua si blocca e
visualizza il messaggio di out of memory
            i = i + 1
        Loop
    End If
    Set rst = Nothing

 Questo è il codice
[CUT]
Ciao Fabio,
Una soluzione lato server sarebbe la cosa ottimale, se ho capito bene il
problema (per ogni x clienti sottoposti a un filtro assegnare ad un cliente
il valore Me!chrSelezione) non dovrebbe essere un grosso problema.
Ma veniamo al tuo Out of memory
Access xp accede a Sql server per mezzo del provider
*Microsoft.Access.OLEDB.10.0* e del Data provider  *SQLOLEDB.1*
Il Provider in uso ignora le impostazioni che hai assegnato all'apertura del
recordset assegnandogli in ogni caso il cursore adOpenStatic.
prova ad aprire una connessione al tuo db in questo modo
--------------
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Open "Provider=SQLOLEDB.1" & _
        ";Data Source=TuoServer" & _
        ";Initial Catalog=TuoDatabase" & _
        ";Integrated Security=SSPI"
--------------
poi apri il tuo recordset con la connessione appena creata
---------------
rst.Open strSQL, Cn, adOpenForwardOnly,adLockReadOnly
---------------
dovresti riscontrare anche un notevole aumento di prestazioni date
dall'effettivo tipo di cursore adOpenForwardOnly.
Ricordati poi di chiudere e distruggere la connessione prima di uscire dalla
sub
------------------
Rst.Close
Set Rst=Nothing
Cn.Close
Set Cn=Nothing
-----------------
Ciao Giorgio

 ha scritto nel
messaggio news:42188a7e$0$32343$5fc...@news.tiscali.it...

Ciao Giorgio
Lato server sarebbe ottimale , ma non riesco a creare un SP dove ad ogni N
record marco il record stesso.
Con questa soluzione 4.863.000 record sono stati analizzati in 40 minuti.
Questa routine forse può essere migliorata con CacheSize e Move, spostando
il puntatore ogni nRecord.
Grazie
Fabio

 record marco il record stesso.
se vuoi prendere spunto da questo esempio che seleziona 200 clienti su una
tabella di 8 milioni prendendo in esame 4 milioni di clienti.
Tempo impiegato per la selezione 9 minuti.
E' la prima volta che suggerisco l'uso dei cursori in T-SQL, di solito li
evito ma in questo caso provando con altre strade non sono riuscito a stare
sotto i 40 minuti :(
una curiositą, hai 17 milioni di nominativi ?? lavori per l'anagrafe
tributaria ? :-)
Ciao Giorgio
-----------------------------
USE TEMPDB
GO
--Creo la tabella Clienti
CREATE TABLE Clienti
(Id int Identity(1,1) Primary Key,
 Nome varchar(50),
 Selezionato Bit default (0))
INSERT Clienti (Nome) VALUES('Cliente')
Declare @i int
SET @i=1
SET NOCOUNT ON
--Inserisco 8 milioni di record
WHILE @i<24 BEGIN
   INSERT Clienti (Nome)
   SELECT Nome
   FROM   Clienti
   SET @i=@i+1
END
--Inizio selezione
Declare @DaSelezionare int,
        @Ogni int,
        @Id Int,
        @Nrec int
SELECT  @DaSelezionare =200,
        @Ogni = 20000,
        @Nrec=0
DECLARE Clienti_Cursor CURSOR FAST_FORWARD FOR
SELECT ID FROM Clienti
WHERE 1=1 -- Qui merri la tua WHERE
ORDER BY ID
OPEN Clienti_Cursor
FETCH NEXT FROM Clienti_Cursor
INTO @Id
WHILE @@FETCH_STATUS = 0
BEGIN
   SET @Nrec=@Nrec+1
   IF @Nrec % @Ogni=0 BEGIN
      UPDATE Clienti
         SET Selezionato=1
      WHERE  ID=@Id
      SET @DaSelezionare=@DaSelezionare-1
      IF @DaSelezionare=0
         BREAK
   END
   FETCH NEXT FROM Clienti_Cursor
   INTO @ID
END
CLOSE Clienti_Cursor
DEALLOCATE Clienti_Cursor
-- Lista dei 200 clienti selezionati
Select * From Clienti
Where Selezionato = 1
Order By ID
--Pulizia
DROP TABLE Clienti
--------------------------------

 una curiosità, hai 17 milioni di nominativi ?? lavori per l'anagrafe

Ciao Giorgio,
17 milioni di nominativi, ricerche di mercato e telemarketing, estrazione
casuale di nominativi per area e/o regione e/o provincia e/o comune.
Ho fatto delle prove e su 4863175 per marcare 1000 nominativi impiega da 2 a
3 minuti, incredibile.
Questo è il codice:
Private Sub cmdCreaTabellaEsportazione_Click()
    Dim rst As New ADODB.Recordset
    Dim cn As ADODB.Connection
    Dim strSQL, strSQLWHERE As String
    Dim SQLWHEREArea, SQLWHERERegione, SQLWHEREProvincia, SQLWHEREComune, x
As String
    Dim i, iDoEvent As Integer
    Dim nNomiDaEstrarre, nStep, nRecord As Double
    Me!TimeInizio = Time()
    Set cn = New ADODB.Connection
    cn.Open "Provider=SQLOLEDB.1;Data Source=Fabio;Initial
Catalog=Privati;Integrated Security=SSPI"
    If Val(Me!nNominativi) = 0 Then
        MsgBox "N° Nominativi da estrarre zero.", vbCritical + vbOKOnly,
"Attenzione"
        Exit Sub
    End If
    If Me!NMaxArchivioFiltrati < Val(Me!nNominativi) Then
        MsgBox "N° Nominativi da estrarre errato.", vbCritical + vbOKOnly,
"Attenzione"
        Exit Sub
    End If
    If Me!TRArea = "00" Then SQLWHEREArea = ""
    If Me!TRArea <> "00" Then
        SQLWHEREArea = StringaWHERE("NArea", "TRArea")
    End If
    If Me!TRRegione = "00" Then SQLWHERERegione = ""
    If Me!TRRegione <> "00" Then
        SQLWHERERegione = StringaWHERE("IdRegione", "TRRegione")
    End If
    If Me!TRProvincia = "00" Then SQLWHEREProvincia = ""
    If Me!TRProvincia <> "00" Then
        SQLWHEREProvincia = StringaWHERE("IdProvincia", "TRProvincia")
    End If
    If Me!TRComune = "00" Then SQLWHEREComune = ""
    If Me!TRComune <> "00" Then
        SQLWHEREComune = StringaWHERE("IdComune", "TRComune")
    End If
    strSQLWHERE = ""
    If SQLWHEREArea <> "" And SQLWHERERegione = "" And SQLWHEREProvincia =
"" And SQLWHEREComune = "" Then
        strSQLWHERE = SQLWHEREArea
    End If
    If SQLWHEREArea = "" And SQLWHERERegione <> "" And SQLWHEREProvincia =
"" And SQLWHEREComune = "" Then
        strSQLWHERE = SQLWHERERegione
    End If
    If SQLWHEREArea = "" And SQLWHERERegione = "" And SQLWHEREProvincia <>
"" And SQLWHEREComune = "" Then
        strSQLWHERE = SQLWHEREProvincia
    End If
    If SQLWHEREArea = "" And SQLWHERERegione = "" And SQLWHEREProvincia = ""
And SQLWHEREComune <> "" Then
        strSQLWHERE = SQLWHEREComune
    End If
    If SQLWHEREArea <> "" And SQLWHERERegione <> "" And SQLWHEREProvincia =
"" And SQLWHEREComune = "" Then
        strSQLWHERE = SQLWHEREArea & " AND " & SQLWHERERegione
    End If
    If SQLWHEREArea <> "" And SQLWHERERegione = "" And SQLWHEREProvincia <>
"" And SQLWHEREComune = "" Then
        strSQLWHERE = SQLWHEREArea & " AND " & SQLWHEREProvincia
    End If
    If SQLWHEREArea <> "" And SQLWHERERegione = "" And SQLWHEREProvincia =
"" And SQLWHEREComune <> "" Then
        strSQLWHERE = SQLWHEREArea & " AND " & SQLWHEREComune
    End If
    If SQLWHEREArea = "" And SQLWHERERegione <> "" And SQLWHEREProvincia <>
"" And SQLWHEREComune = "" Then
        strSQLWHERE = SQLWHERERegione & " AND " & SQLWHEREProvincia
    End If
    If SQLWHEREArea = "" And SQLWHERERegione <> "" And SQLWHEREProvincia =
"" And SQLWHEREComune <> "" Then
        strSQLWHERE = SQLWHERERegione & " AND " & SQLWHEREComune
    End If
    If SQLWHEREArea = "" And SQLWHERERegione = "" And SQLWHEREProvincia <>
"" And SQLWHEREComune <> "" Then
        strSQLWHERE = SQLWHEREProvincia & " AND " & SQLWHEREComune
    End If
    If SQLWHEREArea <> "" And SQLWHERERegione <> "" And SQLWHEREProvincia <>
"" And SQLWHEREComune = "" Then
        strSQLWHERE = SQLWHEREArea & " AND " & SQLWHERERegione & " AND " &
SQLWHEREProvincia
    End If
    If SQLWHEREArea <> "" And SQLWHERERegione <> "" And SQLWHEREProvincia =
"" And SQLWHEREComune <> "" Then
        strSQLWHERE = SQLWHEREArea & " AND " & SQLWHERERegione & " AND " &
SQLWHEREComune
    End If
    If SQLWHEREArea <> "" And SQLWHERERegione = "" And SQLWHEREProvincia <>
"" And SQLWHEREComune <> "" Then
        strSQLWHERE = SQLWHEREArea & " AND " & SQLWHEREProvincia & " AND " &
SQLWHEREComune
    End If
    If SQLWHEREArea = "" And SQLWHERERegione <> "" And SQLWHEREProvincia <>
"" And SQLWHEREComune <> "" Then
        strSQLWHERE = SQLWHERERegione & " AND " & SQLWHEREProvincia & " AND
" & SQLWHEREComune
    End If
    If SQLWHEREArea <> "" And SQLWHERERegione <> "" And SQLWHEREProvincia <>
"" And SQLWHEREComune <> "" Then
        strSQLWHERE = SQLWHEREArea & " AND " & SQLWHERERegione & " AND " &
SQLWHEREProvincia & " AND " & SQLWHEREComune
    End If
    nStep = Me!NMaxArchivioFiltrati \ Me!nNominativi     'operatore \ divide
restituendo solo intero
    If nStep < 1 Then nStep = 1
    i = 1
    nNomiDaEstrarre = 0
    If SQLWHEREArea = "" And SQLWHERERegione = "" And SQLWHEREProvincia = ""
And SQLWHEREComune = "" Then
        strSQL = "SELECT Id FROM TPrivati WHERE (Selezionato IS NULL)"
    Else
        strSQL = "SELECT Id FROM TPrivati WHERE (Selezionato IS NULL) AND "
& strSQLWHERE
    End If
    Me!ProgressBar2.Min = 0
    Me!ProgressBar2.Max = Val(Me!nNominativi)
    rst.Open strSQL, cn, adOpenForwardOnly, adLockReadOnly
    If RecordsetisEmpty(rst) = 0 Then
        rst.MoveFirst
'Inizio nuovo ciclo
        rst.CacheSize = 500000              ' imposto la quantità di record
da anilizzare, dalle prove fatte fino a questo momento, dovrebbe essere il
numero ottimale.
        Do While Not rst.EOF
            DoCmd.RunSQL "EXEC StP_CampoSelezione_Aggiorna " & rst!Id & ", "
& Me!chrSelezione
            nNomiDaEstrarre = nNomiDaEstrarre + 1
            Me!ProgressBar2.Object.Value = nNomiDaEstrarre
            If nNomiDaEstrarre = Val(Me!nNominativi) Then Exit Do
            rst.Move nStep
'sposto il cursore ogni nstep senza dover scorrere tutta la tabella
            iDoEvent = DoEvents()
        Loop
'Fine nuovo ciclo
'Vecchio ciclo 40 minuti ' scorro tutta la tabella di 4863175
        'Do While Not rst.EOF
        '    If i = nStep Then
        '        DoCmd.RunSQL "EXEC StP_CampoSelezione_Aggiorna " & rst!Id &
", " & Me!chrSelezione
        '        i = 1
        '        nNomiDaEstrarre = nNomiDaEstrarre + 1
        '        Me!ProgressBar2.Object.Value = nNomiDaEstrarre
        '        If nNomiDaEstrarre = Val(Me!nNominativi) Then Exit Do
        '    End If
        '    rst.MoveNext
        '    i = i + 1
        '    Me!ProgressBar1.Object.Value = i
        'Loop
'Fine vecchio ciclo
    End If
    Set rst = Nothing
    cn.Close
    Set cn = Nothing
    Me!TimeFine = Time()
    Me!NTRDisponibili = Me!NTRDisponibili - Val(Me!nNominativi)
    MsgBox "Selezione terminata"
End Sub
Grazie per il codice
Ciao Fabio


vero, che bisogno c'è di passarseli uno alla volta ? complimenti :-)
ho provato la stessa tecnica in T-SQL e ottengo il risultato dopo 40 Secondi
:-)
Per il momento so che i 2 minuti che hai ottenuto sono un bel risultato ma
se un giorno vorrai provarla con calma .....
Ciao Giorgio
--------------------
-- Inizio selezione
Declare @DaSelezionare int,
        @Ogni int,
        @Id Int
SELECT  @DaSelezionare =200,
        @Ogni = 20000
DECLARE Clienti_Cursor CURSOR SCROLL FOR
SELECT ID FROM Clienti
WHERE 1=1 -- Qui la tua Where
ORDER BY ID
OPEN Clienti_Cursor
FETCH NEXT FROM Clienti_Cursor
INTO @Id
WHILE @@FETCH_STATUS = 0
BEGIN
   UPDATE Clienti
      SET Selezionato=1
   WHERE  ID=@Id
   SET @DaSelezionare=@DaSelezionare-1
   IF @DaSelezionare=0
      BREAK
   FETCH RELATIVE @Ogni FROM Clienti_Cursor
   INTO @ID
END
CLOSE Clienti_Cursor
DEALLOCATE Clienti_Cursor
---------------------