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 / 74102
Accepted
dbafromthecold
dbafromthecold
Asked: 2014-08-16 06:31:56 +0800 CST2014-08-16 06:31:56 +0800 CST 2014-08-16 06:31:56 +0800 CST

Consulta de particionamento

  • 772

Tenho algumas dúvidas sobre o layout físico das tabelas quando elas são particionadas. Eu tenho pesquisado isso, mas ainda estou um pouco inseguro.

Digamos que eu tenha uma tabela existente: -

    CREATE TABLE dbo.[ExampleTable]
     (ID INT IDENTITY(1,1),
      Col1 SYSNAME,
      Col2 SYSNAME,
      CreatedDATE DATE) ON [DATA];

     ALTER TABLE dbo.[ExampleData] ADD CONSTRAINT [PK_ExampleTable] PRIMARY KEY CLUSTERED
     ( [ID] ASC )
     GO

Desejo particionar esta tabela na coluna CreatedDate (todas as partições no mesmo grupo de arquivos para este exemplo), mas não posso ter a coluna como uma chave primária por conta própria. Então eu adiciono a coluna CreatedDate à chave primária: -

    ALTER TABLE dbo.[ExampleTable] DROP CONSTRAINT PRIMARY KEY

    ALTER TABLE dbo.[ExampleTable] ADD CONSTRAINT [PK_ExampleTable] PRIMARY KEY CLUSTERED
    ( [ID] ASC, [CreatedDate] ASC ) ON PartitionScheme(CreatedDate)
    GO

Minha pergunta é como os dados serão classificados? Os dados serão fisicamente divididos em partições pela coluna CreatedDate e depois ordenados pela coluna ID? Ou as partições são lógicas e os dados permanecem ordenados pela coluna ID?

Além disso, o que aconteceria se a coluna ID fosse um GUID? Os dados estariam em partições e então terrivelmente fragmentados dentro dessas partições?

Qualquer conselho seria muito apreciado, obrigado.

André

EDIT:- Adicionando o esquema de partição e a função:-

    DECLARE @CurrentDate DATETIME;

    CREATE PARTITION FUNCTION PF_Example (DATETIME)
    AS RANGE RIGHT 
    FOR VALUES (@CurrentDate+7,@CurrentDate+6,@CurrentDate+5,@CurrentDate+4,
                @CurrentDate+3,@CurrentDate+2,@CurrentDate+1,@CurrentDate,
                @CurrentDate-1,@CurrentDate-2,@CurrentDate-3,@CurrentDate-4,
                @CurrentDate-5,@CurrentDate-6,@CurrentDate-7,@CurrentDate-8);

   CREATE PARTITION SCHEME PS_Example
   AS PARTITION PF_Example
   ALL TO (Data);
sql-server performance
  • 1 1 respostas
  • 3816 Views

1 respostas

  • Voted
  1. Best Answer
    Aaron Bertrand
    2014-08-16T08:47:28+08:002014-08-16T08:47:28+08:00

    Ok, então aqui está um exemplo rápido demonstrando por que - no caso em que a maioria de suas operações (consultas de relatórios, operações de arquivamento, trocas de partição, etc.) identificará intervalos de linhas por data - é melhor agrupar na coluna de particionamento. Vamos ter um esquema e função simples de partição baseada em data:

    CREATE PARTITION FUNCTION DateRange (DATE)
    AS RANGE RIGHT FOR VALUES ('20150101');
    GO
    
    CREATE PARTITION SCHEME DateRangeScheme
    AS PARTITION DateRange ALL TO ([PRIMARY]);
    GO
    

    Em seguida, duas tabelas - uma com uma PK agrupada em ID, Data e um índice não agrupado em Data, e outra com uma PK não agrupada em ID, Data e um índice agrupado em Data.

    CREATE TABLE dbo.PKClustered
    (
      ID INT, 
      dt DATE, 
      filler CHAR(4000)
       CONSTRAINT df_filler_c DEFAULT '' NOT NULL, 
      CONSTRAINT pk_clust PRIMARY KEY CLUSTERED (ID,dt)
    );
    CREATE INDEX dt ON dbo.PKClustered(dt) ON DateRangeScheme(dt);
    
    CREATE TABLE dbo.PKNonClustered
    (
      ID INT, 
      dt DATE, 
      filler CHAR(4000)
       CONSTRAINT df_filler_nc DEFAULT '' NOT NULL, 
      CONSTRAINT pk_nonclust PRIMARY KEY NONCLUSTERED (ID,dt)
    );
    CREATE CLUSTERED INDEX dt ON dbo.PKNonClustered(dt) ON DateRangeScheme(dt);
    

    Agora preencha-os com alguns dados:

    INSERT dbo.PKClustered(ID, dt) SELECT TOP (100) Number, '20141231'
      FROM master.dbo.spt_values WHERE [type] = N'P' ORDER BY Number;
    
    INSERT dbo.PKClustered(ID, dt) SELECT TOP (50) Number, '20150101'
      FROM master.dbo.spt_values WHERE [type] = N'P' ORDER BY Number DESC;
    
    INSERT dbo.PKNonClustered(ID, dt) SELECT ID, dt FROM dbo.PKClustered;
    

    Portanto, devemos ter 100 linhas na partição 1 e 50 linhas na partição 2, certo? sys.partitionsconfirma:

    SELECT [table] = o.name, [index] = i.name, 
      p.partition_number, p.[rows]
    FROM sys.tables AS o
    INNER JOIN sys.indexes AS i
    ON o.[object_id] = i.[object_id]
    INNER JOIN sys.partitions AS p
    ON i.[object_id] = p.[object_id]
    AND i.index_id = p.index_id
    WHERE o.name LIKE N'PK%Clustered'
    ORDER BY o.name, i.name;
    

    Resultados:

    insira a descrição da imagem aqui

    Observe que em ambos os casos os dados no PK são todos armazenados em uma única partição. Como isso afeta as consultas? Bem, considere estes quatro, que provavelmente são típicos (além do SELECT *, usado apenas para concisão):

    SELECT * FROM dbo.PKClustered WHERE dt >= '20150101';
    SELECT * FROM dbo.PKNonClustered WHERE dt >= '20150101';
    
    DELETE dbo.PKClustered WHERE dt >= '20140101' AND dt < '20150101';
    DELETE dbo.PKNonClustered WHERE dt >= '20140101' AND dt < '20150101';
    

    Aqui estão alguns resultados do SQL Sentry Plan Explorer :*

    Custos estimados e métricas reais de tempo de execução:

    insira a descrição da imagem aqui

    O SELECT *contra o PK não clusterizado executou uma busca de índice clusterizado eficiente, acessando apenas uma única partição:

    insira a descrição da imagem aqui

    insira a descrição da imagem aqui

    Quando o PK está em cluster, ele decide executar uma varredura de índice em cluster, o que significa que não pode eliminar partições, levando a mais leituras e, portanto, a um custo de E/S mais alto. Interessante notar, também, que a varredura não é ordenada.

    insira a descrição da imagem aqui

    insira a descrição da imagem aqui

    Coisas semelhantes acontecem com o delete. A parte mais cara da operação de exclusão em ambos os casos é a exclusão do índice clusterizado; ter o benefício da eliminação de partições torna o PK não clusterizado muito mais desejável para suportar esta operação (mesmo que, no final das contas, as leituras necessárias e superiores sejam aproximadamente as mesmas).

    insira a descrição da imagem aqui

    insira a descrição da imagem aqui

    Com o PK clusterizado, as linhas de origem são encontradas com uma busca (que você pode esperar ser mais eficiente), mas, novamente, a maior parte do trabalho é executada pela exclusão subsequente, portanto, pelo menos neste tamanho, não tem muito impacto em tudo:

    insira a descrição da imagem aqui

    insira a descrição da imagem aqui

    Agora, em volumes muito mais altos, essa varredura inicial pode acabar inclinando a balança na outra direção, então você terá que testar.

    É claro que, nesse limite inferior, isso tem um impacto negativo nas consultas de linha única em que você identifica por ID, pois normalmente identifica a linha por uma busca de índice e, em seguida, precisa fazer uma pesquisa, em vez de uma busca de índice clusterizado único. Vamos considerar essas duas consultas (novamente, em relação a SELECT *, faça o que eu digo, não o que eu faço):

    SELECT * FROM dbo.PKClustered WHERE ID = 2045;
    SELECT * FROM dbo.PKNonClustered WHERE ID = 2045;
    

    Resultados do Plan Explorer:

    insira a descrição da imagem aqui

    O primeiro é simples, precisa apenas de uma busca de índice clusterizado (e, portanto, sem pesquisas):

    insira a descrição da imagem aqui

    Mas, como mencionado, o segundo decide uma busca não particionada contra o PK, mas uma pesquisa de chave particionada . Nesse caso, isso acaba sendo mais caro, mas nem sempre, e nem sempre pode ser a escolha do otimizador.

    insira a descrição da imagem aqui

    O mesmo tipo de coisa pode acontecer com certas consultas de junção, dependendo de quantas linhas e como a junção é construída.

    E, novamente, as escolhas do otimizador aqui geralmente dependem do volume. Enfim: depende . Minha escolha com as informações que você forneceu seria agrupar na chave de particionamento e usar um PK não agrupado. E eu evitaria fortemente usar um GUID para esse ID em ambos os casos - embora essa distribuição possa ser boa para inserções se você estiver tentando inserir 8 bilhões de linhas por segundo, isso não ajudará em nada mais que você esteja fazendo.

    Outra opção é usar um único PK combinado em Date primeiro, depois ID:

    CREATE TABLE dbo.PKCombined
    (
      ID INT, 
      dt DATE, 
      filler CHAR(4000)
       CONSTRAINT df_filler_comb DEFAULT '' NOT NULL, 
      CONSTRAINT pk_comb PRIMARY KEY CLUSTERED (dt,ID) ON DateRangeScheme(dt)
    );
    

    Isso obviamente resulta em menos linhas sendo armazenadas em menos páginas (nenhum índice não clusterizado para manter, por exemplo):

    SELECT [table] = o.name, 
      [rows] = SUM(row_count), 
      [pages] = SUM(used_page_count),
      [size_in_kb] = 8.192*SUM(used_page_count)
    FROM sys.tables AS o
    INNER JOIN sys.indexes AS i
    ON o.[object_id] = i.[object_id]
    INNER JOIN sys.dm_db_partition_stats AS p
    ON i.[object_id] = p.[object_id]
    AND i.index_id = p.index_id
    WHERE o.name LIKE N'PK%'
    GROUP BY o.name
    ORDER BY o.name;
    

    Resultados:

    insira a descrição da imagem aqui

    Mas como isso afeta essas outras consultas? O SELECT *é idêntico ao da SELECT *versão PK sem cluster; uma busca simples de índice clusterizado. O DELETE, no entanto, é um plano muito mais simples:

    insira a descrição da imagem aqui

    A busca de linha única, no entanto, acaba sendo muito mais cara:

    insira a descrição da imagem aqui

    Provavelmente, você pode combater isso com um índice de cobertura não clusterizado no ID, que converteria a varredura em uma busca (com uma pesquisa se o índice não for de cobertura), mas ainda não se beneficiaria da eliminação da partição.

    * Isenção de responsabilidade: eu trabalho para o SQL Sentry.

    • 7

relate perguntas

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

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

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

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