AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 13674
Accepted
datagod
datagod
Asked: 2012-02-23 09:04:48 +0800 CST2012-02-23 09:04:48 +0800 CST 2012-02-23 09:04:48 +0800 CST

Qual é a melhor abordagem para analisar uma grande quantidade de strings?

  • 772

Tenho uma tabela com mais de 400.000.000 de registros e estou procurando conselhos sobre como analisá-la rapidamente.

TheNameTable
(
  NameID  int primary key,
  TheName varchar(500)
)

Os nomes são armazenados assim: "FirstName, LastName" (não é minha tabela, apenas o que tenho para trabalhar)

Preciso extrair uma lista exclusiva de sobrenomes. Minha ideia inicial é processar a tabela em uma série de lotes (digamos, 50.000 registros por vez), usando o NameID para controlar os intervalos do lote. Eu usaria as funções de string incorporadas do SQL para quebrar a string no "," e manter a metade direita da string.

right(TheName,charindex('.',reverse(TheName))-1)

Tenho a sensação de que isso ainda levará MUITO tempo.

Alguém aí tem alguma outra ideia?

Valeria a pena simplesmente exportar os dados e processar o arquivo fora do banco de dados?

A solução com a qual fui:

Conforme sugerido, criei duas colunas computadas. Um para o primeiro nome, outro para o sobrenome. Eles não são persistidos, pois tenho espaço limitado.

alter table TheNameTable 
add LastName as substring(TheName, charindex(',',TheName)+1,1000)

alter table TheNameTable 
add FirstName as left(TheName,charindex(',',TheName)-1)

Pedi aos administradores um aumento temporário na RAM, eles aumentaram a VM para 32 GB.

Criei uma nova tabela, com colunas para FirstName e LastName. Coloquei um índice composto exclusivo nas colunas, mas especifiquei IGNORE_DUP_KEY = ON.

Acabei de inserir os primeiros 1.000.000 de registros. Ele filtrou 125.000 duplicatas. A instrução inteira levou 9 segundos para ser executada.

Essa é a velocidade que eu estava procurando!

sql-server
  • 4 4 respostas
  • 4726 Views

4 respostas

  • Voted
  1. Best Answer
    Darin Strait
    2012-02-23T10:14:06+08:002012-02-23T10:14:06+08:00

    400 milhões de nomes é muito. Eu estou lá? ;-)

    Meu pressentimento diz que usar substring não será muito mais lento do que codificar algo por meio do CLR. Sou um cara do SQL, fiz uma boa quantidade de análises simples no passado (2000 ou 2005) e estava envolvido no que seria um esquema de análise muito complicado (endereços, em todo o mundo) escrito em c e chamado por meio de um xproc até descobrirmos que o código "nativo" do protótipo não era mais rápido do que a mesma coisa escrita com funções tsql.

    Se você quiser usar uma linguagem diferente de tsql, sugiro escrever um CLR em c# ou vb.net. Para coisas simples, não é difícil codificar em CLR. Passei de newb para ter alguns diretórios de trabalho e utilitários de arquivo em menos de uma manhã. Existem muitos exemplos de procedimentos clr simples na rede. e você não terá que aprender nada (ou instalar o visual studio) para escrevê-lo em tsql

    Não importa o que aconteça, você terá que passar pela mesa pelo menos uma vez. Se você exportar, analisar e colocar de volta o que não é uma pequena quantidade de dados, isso é muito tempo. Você pode garantir que sua fonte não vai mudar nesse meio tempo?

    Aqui está o que sempre parece surpreender a todos: o que acontece com os dados analisados? Onde isso acaba? Você pretende atualizar a linha, talvez haja colunas de sobrenome e nome que você não mostra em seu exemplo?

    Se você fizer isso, e essas colunas forem nulas ou tiverem cadeias de comprimento zero nelas, você pode descobrir que o desempenho da instrução de atualização é muito ruim porque o sql pode ter que dividir as páginas para armazenar o sobrenome.

    Em outras palavras, seu problema de desempenho não está analisando, mas armazenando os dados analisados. Muitas vezes, isso é pior do que inserir os dados em outra tabela. Além disso, todas essas divisões de página fragmentarão sua tabela e farão com que o desempenho da consulta caia, o que pode enfurecer seu dba porque ele terá que executar um procedimento de desfragmentação na tabela (grande).

    Aqui está um último pensamento: você realmente precisa armazenar os dados analisados? Você pode se safar com uma coluna computada que calcula o sobrenome na hora? Esses são indexáveis, com certas condições , se você precisar disso. Outra abordagem seria uma exibição que expõe as colunas da tabela, bem como sua "coluna de sobrenome analisada".

    • 6
  2. Ash Burlaczenko
    2012-02-23T09:21:42+08:002012-02-23T09:21:42+08:00

    Pode ser mais rápido escrever um pequeno script em outra linguagem como c# por exemplo, para extrair todos os dados da tabela e manipulá-los.

    Você pode fazer o que quiser com os dados, enviando-os para outro lugar ou de volta ao banco de dados usando o BCP.

    • 3
  3. ConcernedOfTunbridgeWells
    2012-02-23T09:43:13+08:002012-02-23T09:43:13+08:00

    Se você tiver acesso a um conjunto de utilitários de shell unix (consulte gnu win32 se precisar obter alguns que sejam executados no Windows), poderá exportar a coluna TheNamee processá-la com um pipeline de shell nas linhas de:

    cut -d, -f2 | sed 's/ //g' | sort | uniq
    

    O processo de exportação será bastante caro, no entanto. No SQL Server, você pode criar uma tabela temporária com os sobrenomes usando uma consulta nas linhas de:

    select distinct rtrim(ltrim (substring (Name, charindex (',', TheName) + 1, 100)))
      into #DistinctSurnames
      from TheNameTable
    

    De qualquer maneira que você olhe, você está pronto para uma varredura de mesa. A exportação provavelmente seria mais cara do que o processamento distinto na consulta, portanto, suponho que a consulta seria mais rápida.

    • 3
  4. WernerCD
    2012-02-23T18:15:32+08:002012-02-23T18:15:32+08:00

    Tenho aprendido muito sobre o processamento do SQL Server e pensei em tentar isso com um Cursor. Meu processo de pensamento é criar outro banco de dados (talvez até outra instância) para que você possa truncar os logs conforme necessário, já que este é um banco de dados de "relatórios" e você deseja limitar a interação com os dados "Ativos".

    O cursor seria uma boa ideia, na minha opinião, porque você pode fazer o processamento à medida que avança e, teoricamente, em uma única passagem. Não seria muito difícil

    • Adicione um campo de contagem à tabela LastName, por exemplo, para contar ocorrências de nomes (nome, contagem).
    • Adicione um contador de loop que limpe o log de transações após 1 milhão de loops.
    • Adicione um divisor que divide os nomes em tabelas individuais (LastNameA, LastNameB,... LastNameOther, Invalid)

    Merge é uma construção de 2008+, então isso funcionaria, afaik, se você criasse outra instância e vinculasse a 2000/2005 se não estivesse em 2008+:

    /*
    USE Master;
    IF EXISTS(SELECT name FROM sys.databases WHERE name = 'Original') DROP Database Original;
    GO
    
    CREATE DATABASE Original;
    GO
    
    USE Original;
    GO
    
    IF OBJECT_ID('TheNameTable','U') is not null DROP Table TheNameTable;
    GO
    Create Table TheNameTable (NameID INT Primary Key Identity, TheName varchar(500));
    GO
    INSERT INTO TheNameTable Values('John, Wayne');
    INSERT INTO TheNameTable Values('Wayne, Berry');
    INSERT INTO TheNameTable Values('Bill, Murray');
    INSERT INTO TheNameTable Values('Elvis, Presley');
    INSERT INTO TheNameTable Values('Lady, Gaga');
    INSERT INTO TheNameTable Values('Latoya, Jackson');
    INSERT INTO TheNameTable Values('Michael, Jackson');
    INSERT INTO TheNameTable Values('Tito, Jackson');
    INSERT INTO TheNameTable Values('Randy, Jackson');
    INSERT INTO TheNameTable Values('Prince');
    GO
    */
    SELECT * FROM TheNameTable;
    
    USE Master;
    IF EXISTS(SELECT name FROM sys.databases WHERE name = 'Reporting') DROP Database Reporting;
    GO
    
    CREATE DATABASE Reporting;
    GO
    ALTER DATABASE Reporting SET RECOVERY SIMPLE;
    GO
    
    USE Reporting;
    GO
    
    IF OBJECT_ID('LastName','U') is not null DROP Table LastName;
    GO
    Create Table LastName (Name varchar(500) PRIMARY KEY);
    GO
    
    DECLARE @TheName varchar(500);
    DECLARE @LastName varchar(500);
    DECLARE LastNameCursor Cursor
    FOR 
    Select TheName
    From Original.dbo.TheNameTable;
    
    Open LastNameCursor;
    
    Fetch NEXT FROM LastNameCursor INTO @TheName;
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF (@TheName LIKE '%,%')
        BEGIN
            SET @LastName = right(@TheName,charindex(',',reverse(@TheName))-1);
            MERGE INTO dbo.LastName T
            USING (SELECT @LastName Name) S
                    ON T.Name = S.Name
        --  WHEN MATCHED THEN
        --          Nothing to do here.
            WHEN NOT MATCHED
                    THEN INSERT VALUES (@LastName);
        END
    
        FETCH NEXT FROM LastNameCursor INTO @TheName;
    END
    
    CLOSE LastNameCursor;
    DEALLOCATE LastNameCursor;
    GO
    
    SELECT * FROM Reporting.dbo.LastName;
    GO
    
    • 0

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como ver a lista de bancos de dados no Oracle?

    • 8 respostas
  • Marko Smith

    Quão grande deve ser o mysql innodb_buffer_pool_size?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    restaurar a tabela do arquivo .frm e .ibd?

    • 10 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve