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 / 10263
Accepted
olle
olle
Asked: 2012-01-07 07:04:35 +0800 CST2012-01-07 07:04:35 +0800 CST 2012-01-07 07:04:35 +0800 CST

Coluna de atualização de um grande conjunto de registros com um valor calculado

  • 772

Estou tentando descobrir qual seria uma boa maneira de escrever a pseudoconsulta abaixo no TSQL, levando em consideração que haverá cerca de 50 registros de actualResult e 100.000 registros de previsão por resultado real envolvido.

update prediction
set points = (
    @points = 0
    if(prediction.valueA = actualResult.valueA AND prediction.valueB = actualResult.valueB)
        @points = @points + 3
    if (prediction.valueA = actualResult.valueA OR prediction.valueB = actualResult.valueB)
        @points = @points + 1
    select @points
)   
join actualResult on prediction.actualid = actualResult.id
where actualResult.id in (some subquery)

o que eu estou pensando é:

  • Existe uma maneira de fazer o cálculo que na realidade é mais complexo em linha? No momento, só posso fazê-lo funcionar se colocá-lo em uma função, mas pelo que entendi, isso significa que ele é constantemente recalculado, mesmo que a entrada seja a mesma (o que eu provavelmente atribuo às previsões)
  • Dessa forma bloquearia toda a gama de registros? E se assim for, há uma maneira de evitar isso? Por exemplo, copiando tudo para uma variável de tabela e, em seguida, fazendo o cálculo sobre ela e atualizando os registros assim que todos os cálculos forem feitos?

estou no caminho certo aqui ou você escreveria de uma maneira diferente?

sql-server sql-server-2008
  • 4 4 respostas
  • 2228 Views

4 respostas

  • Voted
  1. Oleg Dok
    2012-01-07T07:27:54+08:002012-01-07T07:27:54+08:00

    Tente isto:

    update prediction
    set points = 
        (
            0 
            + 
            CASE WHEN prediction.valueA = actualResult.valueA AND prediction.valueB = actualResult.valueB
            THEN 3 ELSE 0 END
            +
            CASE WHEN prediction.valueA = actualResult.valueA OR prediction.valueB = actualResult.valueB
            THEN 1 ELSE 0 END
        )   
    join actualResult on prediction.actualid = actualResult.id
    where actualResult.id in (some subquery)
    

    AFAIK - se a função não depende dos dados na consulta, ela chama uma vez por consulta,

    E

    se a função for determinística e vinculada ao esquema - ela não chamará várias vezes para os mesmos dados, MAS deve haver um índice nos dados do argumento E o otimizador deve querer usar esse índice

    Se você deseja bloqueio por linha, use a dica ROWLOCK

    • 1
  2. Best Answer
    Mark Storey-Smith
    2012-01-07T09:19:22+08:002012-01-07T09:19:22+08:00

    Existe uma maneira de fazer o cálculo que na realidade é mais complexo em linha?

    Se você puder dobrar a lógica em uma instrução inline, talvez usando CASE como mostrado abaixo, ela normalmente superará uma UDF escalar (função definida pelo usuário) por ordens de magnitude. O argumento para uma UDF geralmente é o encapsulamento de um cálculo complexo ou comum, mas se for necessário apenas nesta consulta, é melhor inline.

    UPDATE
        p
    SET
        p.Points = p.Points +
                CASE 
                    WHEN p.valueA = a.valueA AND p.valueB = a.valueB THEN 3
                    WHEN p.valueA = a.valueA OR p.valueB = a.valueB THEN 1
                    ELSE 0
                END
    FROM
        dbo.Prediction p
    INNER JOIN
        dbo.ActualResult a
    ON  a.Id = p.ActualId
    WHERE
        a.Id IN (subquery)
    

    Dessa forma bloquearia toda a gama de registros?

    Você precisa entender o conceito de níveis de isolamento para determinar a) o que será bloqueado e talvez mais importante b) o que deve ser bloqueado. Resumindo, no nível de isolamento READ COMMITTED padrão, um bloqueio compartilhado será obtido e imediatamente liberado em cada linha de cada tabela conforme ela é lida para realizar a junção. As linhas na previsão que serão atualizadas serão protegidas com atualização e, em seguida, bloqueios exclusivos nas linhas que serão mantidas até que a instrução (ou transação pai) seja confirmada.

    Dependendo da distribuição e volume de atualizações, você pode encontrar linhas acima substituídas por páginas ou tabelas de pior caso.

    E se assim for, há uma maneira de evitar isso? Por exemplo, copiando tudo para uma variável de tabela e, em seguida, fazendo o cálculo sobre ela e atualizando os registros assim que todos os cálculos forem feitos?

    Você não pode impedir o bloqueio de linhas que estão sendo atualizadas ou inseridas, caso contrário, a conformidade com o ACID seria comprometida. Você pode reduzir o bloqueio nas linhas que estão sendo lidas, mas pode ser necessário considerar o contrário e aumentar o nível de isolamento. Se outros processos inserirem ou atualizarem registros enquanto essa atualização ocorrer, você pode acabar com um erro de cálculo.

    De acordo com os níveis de isolamento no mecanismo de banco de dados ...

    As transações especificam um nível de isolamento que define o grau em que uma transação deve ser isolada de recursos ou modificações de dados feitas por outras transações. Os níveis de isolamento são descritos em termos dos quais efeitos colaterais de simultaneidade, como leituras sujas ou leituras fantasmas, são permitidos.

    Um rastreamento do Profiler em eventos Lock:Acquired/Released e/ou uso do sinalizador de rastreamento 1200 em uma máquina de teste isolada pode ser muito útil para entender a sequência de bloqueios aplicados e liberados em diferentes níveis de isolamento.

    • 1
  3. Brandon
    2012-01-07T13:31:29+08:002012-01-07T13:31:29+08:00

    Outra coisa que você poderia fazer se estiver preocupado em bloquear grandes porções de uma tabela ou envolver um gatilho subjacente em milhares de chamadas ao mesmo tempo é examinar mais uma abordagem de loop/chunk. Dado que você tem ~ 50 registros ActualResult, você pode percorrer esses 1-5 de cada vez e provavelmente obter um desempenho decente. Isso também pode evitar que seus bloqueios de linha se transformem em bloqueios de tabela.

    • 1
  4. a1ex07
    2012-01-07T09:38:31+08:002012-01-07T09:38:31+08:00

    Se o objetivo é manter prediction-se atualizado de acordo com os dados da actualResulttabela, você pode tentar usar uma abordagem diferente. Escreva AFTER INSERT,UPDATE,DELETEo gatilho queUPDATE prediction set valueA = valueA +3(or -,depends on dml) WHERE ....

    • 0

relate perguntas

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

  • Quanto "Padding" coloco em meus índices?

  • Existe um processo do tipo "práticas recomendadas" para os desenvolvedores seguirem para alterações no banco de dados?

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

  • Downgrade do SQL Server 2008 para 2005

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