Jump to content
Fivewin Brasil

Demora em atualizar estrura tabela mysql


marcioe

Recommended Posts

Amigos estou tendo problemas para criar um campo novo em uma tabela com mais de 5 milhões de registros.

Faço mais ou menos assim.

ALTER TABLE ctrc_nf ADD campo char(80) not null AFTER fone;

Daí demora demais mais de uma hora.

O servidor e Linux, e é xeon biprocessado. Com discos SAS, etc.

Será que tem como melhorar isso.

Link to comment
Share on other sites

Não sei se funciona, mas você pode tentar assim:

• Criar um a tabela temporária com a nova estrutura;

• Dar um INSERT INTO tabela_temp (Campo1, Campo2, ...) SELECT Campo1, Campo2, ... FROM tabela_atual

• Dar um DROP TABLE na tabela atual

• Dar um ALTER TABLE tabela_temp RENAME tabela_atual

Este é o método que uso atualmente para modificar estrutura de tabelas, mas ainda não testei com tabelas com grande quantidade de arquivos. Também ainda não testei em ambiente multi-usuário.

Segue o código que uso, para você ter uma ideia. Eu uso a SQLRDD.

Criação de uma tabela:

   // Criação da tabela de itens por revendedora: gas_itens
   aEstr:={}
   AADD( aEstr ,{ "cnpjid", "C", 14, 0 } ) // Revendedor: CNPJ da disk gás/água   
   AADD( aEstr ,{ "itemid", "C", 13, 0 } ) // Item: Código pessoal - pode ser o código de barras do cliente.
   AADD( aEstr ,{ "itdesc", "C", 50, 0 } ) // Item: Descrição
   AADD( aEstr ,{ "itprun", "N", 10, 2 } ) // Item: Valor unitário
   AADD( aEstr ,{ "ittaxa", "N", 10, 2 } ) // Item: Taxa de entrega
   AADD( aEstr ,{ "itfoto", "M", 10, 0 } ) // Item: Imagem do item
   AADD( aEstr ,{ "itmobs", "C",100, 0 } ) // Item: Observação
   IF ! SR_ExistTable( "gas_itens" )
      TRY
         cComm := XB2SqlStr(aEstr, "gas_itens")
         nErr := oSql:Execute( cComm )
      CATCH oErr
	      MsgAlert("Erro ao tentar conectar com o banco de dados."+CRLF+;
	               "Favor verificar sua conexão e tente novamente."+CRLF+CRLF+;
						"Erro: "+oErr:Description, "Ocorreu um erro")
	      FileWrite(ErroFile(), oErr:Description)
         PostQuitMessage( 0 )
         __QUIT()
      END
   else
      lChg := ChkStruct("gas_itens", "", aEstr, oSql, nErr, nPos)
   ENDIF

A função XB2SqlStr()

STATIC FUNCTION XB2SqlStr(aStr, cDBase)
   LOCAL cStrct
   cStrct := "CREATE TABLE `"+LOWER(cDBase)+"` ("
   FOR nF := 1 TO LEN(aStr)
   	 IF LOWER(aStr[nF,1]) !=  "sr_recno"
	       IF nF > 1 ; cStrct += ", " ; ENDIF // Mais de um campo
	       cStrct += "`"+LOWER(aStr[nF,1])+"` "+SetFType(aStr[nF,2],aStr[nF,3],aStr[nF,4])
       ENDIF
   NEXT
   IF LEN(aStr) > 0 ; cStrct += ", " ; ENDIF // Já acrescentado algum campo
   cStrct += "`sr_recno` BIGINT (15) NOT NULL UNIQUE AUTO_INCREMENT)" // Sempre criar o 'sr_recno' no final, para compatibilizar com SQLRDD
RETURN( cStrct )

STATIC FUNCTION SetFType(cTipo,nSize,nDeci)
   LOCAL cFType
   IF cTipo = "C" ; cFType := "char("+ALLTRIM(STR(nSize))+")"
   ELSEIF cTipo = "M" ; cFType := "mediumblob"
   ELSEIF cTipo = "N" ; cFType := "double("+ALLTRIM(STR(nSize))+","+ALLTRIM(STR(nDeci))+")"
   ELSEIF cTipo = "L" ; cFType := "tinyint(4)"
   ELSEIF cTipo = "D" ; cFType := "date"
   ENDIF
RETURN(cFType)

A função que faz a modificação na estrutura, se necessário: ChkStruct()

STATIC FUNCTION ChkStruct(cTable, cUniq, aStrct, oSql, nErr, nPos)
   LOCAL lChangd, cComm, aNewStr, aOldStr, aChange, aImport, cImport, aArray := {}, cTmpTable := cTable+"_old"
   aNewStr := aStrct
   nScan := ASCAN(aNewStr, {|nC|nC[1]="sr_recno"})
   IF nScan = 0
	   AADD(aNewStr, {"sr_recno", "N", 15, 0}) // SQLRDD acrescenta este campo ao criar a tabela
   ENDIF

   cSay := "Verificando a tabela '"+cTable+"'"
   oSay:SetText(cSay)
   oSay:Refresh()

   IF ! l_Check ; RETURN .F.; ENDIF
   
   // Obter a estrutura da tabela atual.
   nErr := 0
   TRY
      cComm := "SELECT * FROM "+cTable+" LIMIT 1"
      nErr := oSql:Execute( cComm )
      oSql:iniFields(.f.)
      aOldStr := oSql:aFields // Para pegar a estrutura
   CATCH
      ShowMsgTray("Não foi possível testar a tabela '"+cTable+"'", "Aguarde...") ; SysWait(1)
      RETURN .F.
   END TRY

   // Comparar com a estrutura de aStrct
   lChangd := .F.
   aChange := {}
   aImport := {}
   cImport := ""
   TRY
      FOR nX := 1 TO LEN(aNewStr) // Verifica se foi acrescentado algum campo ou se mudou o tamanho de algum.
          cFild:=Lower(aNewStr[nX,1])
          cType:=aNewStr[nX,2]
          cSize:=STRZERO(aNewStr[nX,3], 4)
          cDeci:=STRZERO(aNewStr[nX,4], 3)
          nElem := ASCAN(aOldStr, {|aNro| Lower(aNro[1]) == cFild})
          IF nElem > 0
          	 if cFild != "sr_recno" // Não considerar erro de estrutura deste
	             IF cType != aOldStr[nElem,2] .OR. ;
	                cSize != STRZERO(aOldStr[nElem,3], 4) .OR. ;
	                cDeci != STRZERO(aOldStr[nElem,4], 3)
	                lChangd := .T. // Mudou o tamanho de um campo
	                aadd(aChange, {cFild, "Modificou a estrutura"})
	             ENDIF
             endif
          ELSE
             lChangd := .T. // Foi removido algum campo
             aadd(aChange, {cFild, "Campo acrescentado"})
          ENDIF
      NEXT
      FOR nX := 1 TO LEN(aOldStr) // Verifica se foi excluindo algum compo
          cFild := Lower(aOldStr[nX,1])
          nElem := ASCAN(aNewStr, {|aNro| Lower(aNro[1]) == cFild})
          IF nElem = 0
             lChangd := .T. // Algum campo foi removido
             aadd(aChange, {cFild, "Campo removido"})
          ELSE
             AADD(aImport, cFild) // Para pegar só os campos que existem nas duas tabelas.
          ENDIF
      NEXT
      IF lChangd
         // Determinar quais campos serão importados da tabela temporária
         FOR nX := 1 TO LEN(aImport)
             IF Lower(aImport[nX]) != "sr_recno" // Apenas um teste
                IF ! EMPTY(cImport) ; cImport += ", " ; ENDIF
                cImport += Lower(aImport[nX]) // Pegar só os campos que existem nas duas tabelas.
             ENDIF
         NEXT
      ENDIF
   CATCH
      ShowMsgTray("Não foi possível testar a tabela '"+cTable+"'", "Aguarde...")
      SysWait(0.5)
      RETURN .F.
   END TRY

   IF SR_ExistTable( cTmpTable )
      cComm := "DROP TABLE "+cTmpTable
      TRY
         nErr := oSql:Execute( cComm )
         if nErr == 0
            ShowMsgTray("Executou "+cComm, "Ok") ; SysWait(0.5)
         else
            ShowMsgTray("Não foi preciso executar "+cComm, "Aguarde...") ; SysWait(2)
         endif
      CATCH
         ShowMsgTray("Não foi possível excluir a tabela '"+cTmpTable+"'", "Erro...")
         SysWait(0.5)
         RETURN .F.
      END TRY
   ENDIF

   IF ! lChangd
      ShowMsgTray("Extrutura de '"+cTable+"' sem alterações.", "Ok") ; SysWait(0.5)
      RETURN .F.
   ENDIF

   // Ver se tem itens na tabela
   oSql:Exec("SELECT * FROM "+cTable,,.t.,@aArray,,,0)

   cComm := "ALTER TABLE "+cTable+" RENAME "+cTmpTable
   nErr := oSql:Execute( cComm )
   if nErr == 0
      ShowMsgTray("Executou "+cComm, "Ok") ; SysWait(0.5)
   else
      ShowMsgTray("Não foi possível executar "+cComm, "Aguarde...") ; SysWait(2)
      RETURN .F.
   endif

   l_Err := .F.
	TRY
      cComm := XB2SqlStr(aStrct, cTable)
      nErr := oSql:Execute( cComm )
      ShowMsgTray("Criou "+cTable, "Ok") ; SysWait(0.5)
   CATCH oErr
      FileWrite(ErroFile(), oErr:Description)
	   l_Err := .T.
   END TRY
   IF l_Err
	   cComm := "ALTER TABLE "+cTmpTable+" RENAME "+cTable
	   nErr := oSql:Execute( cComm )
      ShowMsgTray("Erro ao tentar criar a nova a tabela: Executado RollBack '"+cTable+"'.","Erro") ; SysWait(1)
      RETURN .F.
   ENDIF
   IF ! EMPTY(cUniq)
      TRY
         cSql := "ALTER TABLE "+cTable+" ADD UNIQUE ("+cUniq+")"
         nErr := oSql:Execute(cSql)
         ShowMsgTray("Executada query "+cSql,"Retorno: "+cValToChar(nErr)) ; SysWait(1)
      CATCH
      END TRY
   ENDIF

   // Importar dados da tabela temporária
   IF LEN(aArray) > 0
      TRY
	      cQury := "INSERT INTO "+cTable+" ("+cImport+") SELECT "+cImport+" FROM "+cTmpTable
	      BEGIN TRANSACTION
	      nErr := oSql:Execute(cQury)
	      END TRANSACTION
	      oSql:Commit()
	      ShowMsgTray("Executou "+cComm, "Ok") ; SysWait(0.5)
      CATCH oErr
	      MsgAlert("Erro ao tentar conectar com o banco de dados."+CRLF+;
	               "Favor verificar sua conexão e tente novamente."+CRLF+CRLF+;
						"Erro: "+oErr:Description, "Ocorreu um erro")
	      FileWrite(ErroFile(), oErr:Description)
      END TRY
   ENDIF

   // Excluir a tabela temporária
   cComm := "DROP TABLE "+cTmpTable
   nErr := oSql:Execute( cComm )
   if nErr == 0
      ShowMsgTray("Executou "+cComm, "Ok") ; SysWait(0.5)
   else
      ShowMsgTray("Não foi preciso executar "+cComm, "Aguarde...") ; SysWait(2)
   endif
RETURN( .t. )
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...