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 / 120756
Accepted
Erik
Erik
Asked: 2015-11-12 08:04:11 +0800 CST2015-11-12 08:04:11 +0800 CST 2015-11-12 08:04:11 +0800 CST

Por que os TVPs devem ser READONLY e por que os parâmetros de outros tipos não podem ser READONLY

  • 772

De acordo com este blog , os parâmetros para uma função ou um procedimento armazenado são essencialmente passados ​​por valor se não forem OUTPUTparâmetros e tratados essencialmente como uma versão mais segura de passagem por referência se forem OUTPUTparâmetros.

A princípio, pensei que o objetivo de forçar a declaração do TVP READONLYera sinalizar claramente aos desenvolvedores que o TVP não pode ser usado como OUTPUTparâmetro, mas deve haver mais coisas acontecendo porque não podemos declarar não-TVP como READONLY. Por exemplo, o seguinte falha:

create procedure [dbo].[test]
@a int readonly
as
    select @a

Msg 346, Nível 15, Estado 1, Teste de procedimento
O parâmetro "@a" não pode ser declarado READONLY, pois não é um parâmetro com valor de tabela.

  1. Como as estatísticas não são armazenadas no TVP, qual é a lógica por trás da prevenção de operações DML?
  2. Está relacionado a não querer que o TVP seja OUTPUTparâmetro por algum motivo?
sql-server parameter
  • 2 2 respostas
  • 12146 Views

2 respostas

  • Voted
  1. Best Answer
    Solomon Rutzky
    2015-11-12T10:04:21+08:002015-11-12T10:04:21+08:00

    A explicação parece estar ligada a uma combinação de: a) um detalhe do blog vinculado que não foi mencionado nesta pergunta, b) a pragmática dos TVPs se encaixando em como os parâmetros sempre foram passados ​​para dentro e para fora, c) e a natureza de variáveis ​​de tabela.

    1. O detalhe ausente contido na postagem do blog vinculado é exatamente como as variáveis ​​são passadas para dentro e para fora dos Procedimentos e Funções Armazenadas (que se relaciona com a frase na Questão de "uma versão mais segura de passagem por referência se forem parâmetros OUTPUT") :

      O TSQL usa uma semântica copy-in/copy-out para passar parâmetros para funções e procedimentos armazenados....

      ...quando o proc armazenado termina de executar (sem encontrar um erro) é feito um copy-out que atualiza o parâmetro passado com quaisquer alterações que foram feitas nele no proc armazenado.

      O benefício real dessa abordagem está no caso de erro. Se ocorrer um erro no meio da execução de um procedimento armazenado, quaisquer alterações feitas nos parâmetros não serão propagadas de volta para o chamador.

      Se a palavra-chave OUTPUT não estiver presente, nenhuma cópia será feita.

      Resumindo: os
      parâmetros para stored procs nunca refletem a execução parcial da stored proc se ela encontrar um erro.

      A parte 1 deste quebra-cabeça é que os parâmetros são sempre passados ​​"por valor". E é somente quando o parâmetro é marcado como OUTPUT e o procedimento armazenado é concluído com êxito que o valor atual é realmente enviado de volta. Se OUTPUTos valores fossem realmente passados ​​"por referência", então o ponteiro para o local na memória dessa variável seria o que foi passado, não o valor em si. E se você passar o ponteiro (ou seja, endereço de memória), todas as alterações feitas serão refletidas imediatamente, mesmo que a próxima linha do procedimento armazenado cause um erro e aborte a execução.

      Para resumir a Parte 1: os valores das variáveis ​​são sempre copiados; eles não são referenciados por seu endereço de memória.

    2. Com a Parte 1 em mente, uma política de sempre copiar valores de variáveis ​​pode levar a problemas de recursos quando a variável transmitida for muito grande. Não testei para ver como os tipos de blob são tratados ( VARCHAR(MAX), NVARCHAR(MAX), VARBINARY(MAX), XML, e aqueles que não devem mais ser usados: TEXT, NTEXTe IMAGE), mas é seguro dizer que qualquer tabela de dados passada pode ser bem grande. Faria sentido para aqueles que desenvolvem o recurso TVP desejar uma verdadeira capacidade de "passar por referência" para evitar que seu novo recurso legal destrua um número saudável de sistemas (ou seja, desejar uma abordagem mais escalável). Como você pode ver na documentação , foi isso que eles fizeram:

      Transact-SQL passa parâmetros com valor de tabela para rotinas por referência para evitar fazer uma cópia dos dados de entrada.

      Além disso, essa preocupação com o gerenciamento de memória não era um conceito novo, pois pode ser encontrada na API SQLCLR que foi introduzida no SQL Server 2005 (os TVPs foram introduzidos no SQL Server 2008). Ao passar NVARCHARe VARBINARYdados para o código SQLCLR (ou seja, parâmetros de entrada nos métodos .NET em um Assembly SQLCLR), você tem a opção de ir com a abordagem "por valor" usando um SqlStringou SqlBinaryrespectivamente, ou você pode ir com a abordagem "por referência "abordagem usando um SqlCharsou SqlBytesrespectivamente. Os tipos SqlCharse SqlBytespermitem o streaming completo dos dados no .NET CLR, de forma que você possa obter pequenos blocos de valores grandes, em vez de copiar um valor inteiro de 200 MB (até 2 GB, certo).

      Para resumir a Parte 2: os TVPs, por sua própria natureza, teriam uma propensão a consumir muita memória (e, portanto, deteriorar o desempenho) se permanecessem dentro do modelo "sempre copiar o valor". Portanto, os TVPs fazem uma verdadeira "passagem por referência".

    3. A parte final é por que a Parte 2 é importante: por que passar um TVP verdadeiramente "por referência" em vez de fazer uma cópia dele mudaria alguma coisa. E isso é respondido pelo objetivo de design que é a base da Parte 1: Procedimentos armazenados que não são concluídos com êxito não devem alterar, de forma alguma, nenhum dos parâmetros de entrada, sejam eles marcados como OUTPUTou não. Permitir operações DML teria um efeito imediato no valor do TVP conforme ele existe no contexto de chamada (já que passar por referência significa que você está alterando o que foi passado, não uma cópia do que foi passado).

      Agora, alguém, em algum lugar, provavelmente está falando com seu monitor dizendo: "Bem, apenas construa uma instalação automágica para reverter quaisquer alterações feitas nos parâmetros TVP se alguma tiver sido passada para o procedimento armazenado. Duh. Problema resolvido." Não tão rápido. É aqui que entra a natureza das Variáveis ​​de Tabela: as alterações feitas nas Variáveis ​​de Tabela não são vinculadas por Transações! Portanto, não há como reverter as alterações. E, na verdade, esse é um truque usado para salvar as informações geradas em uma transação, caso haja a necessidade de uma reversão :-).

      Para resumir a Parte 3: Table-Variables não permitem "desfazer" alterações feitas a elas no caso de um erro que faça com que o Stored Procedure seja abortado. E isso viola o objetivo do projeto de ter parâmetros que nunca refletem a execução parcial (Parte 1).

    Portanto: a READONLYpalavra-chave é necessária para evitar operações DML em TVPs, pois são variáveis ​​de tabela que são realmente passadas "por referência" e, portanto, qualquer modificação nelas seria refletida imediatamente, mesmo que o procedimento armazenado encontrasse um erro e não houvesse outra maneira de evitar isso.

    Além disso, parâmetros de outros tipos de dados não podem ser usados READONLY​​porque já são cópias do que foi passado e, portanto, não protegeriam nada que já não estivesse protegido. Isso, e a maneira como os parâmetros dos outros tipos de dados funcionam, foi planejado para ser leitura-gravação, portanto, provavelmente seria ainda mais trabalhoso alterar essa API para incluir agora um conceito somente leitura.

    • 21
  2. Paul White
    2016-01-27T04:47:14+08:002016-01-27T04:47:14+08:00

    Resposta do Community Wiki gerada a partir de um comentário sobre a pergunta de Martin Smith

    Existe um item Connect ativo (enviado por Erland Sommarskog) para isso:

    Relaxe a restrição de que os parâmetros da tabela devem ser somente leitura quando os SPs chamam uns aos outros

    A única resposta da Microsoft até agora diz (ênfase adicionada):

    Obrigado pelo feedback sobre isso. Recebemos feedback semelhante de um grande número de clientes. Permitir que os parâmetros com valor de tabela sejam lidos/gravados envolve bastante trabalho no lado do SQL Engine, bem como nos protocolos do cliente. Devido a restrições de tempo/recursos, bem como outras prioridades, não poderemos assumir este trabalho como parte do lançamento do SQL Server 2008. No entanto, investigamos esse problema e temos isso firmemente em nosso radar para resolver como parte da próxima versão do SQL Server. Agradecemos e agradecemos o feedback aqui.

    Srini Acharya
    Gerente Sênior de Programa
    SQL Server Relational Engine

    • 7

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

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 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

    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
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • 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
    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

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