Archive

Posts Tagged ‘Windows Function’

Calculo SQL Server com Windows Function

Ola galera, bom dia(Agora já é tarde, tive que parar pra resolver umas “buchinhas”, voltando após almoço e globo esporte). Blz ?
Hoje iremos fazer uma query usando as windows Function do SQL Server.Esse post  foi originado de uma query que tivemos que criar aqui na empresa. E a maneira mais “elegante” de escrever a  query foi usando as Windows Function.
Tendo as seguintes informações em um arquivo .xls, que me foi passado por um amigo desenvolvedor:
TabelaA

 

TabelaB

E o mesmo deseja o seguinte resultado as informações:

 

Vou explicar os calculos:

primeira Coluna “SomaProdutos” é a soma dos produtos das duas tabelas por IdPeriodo
Ex: A tabela A e a Tabela B armazena a informação de Valor para o periodo  1.
A soma dos valores 77 + 55 é  igual a 132 e assim sucessivamente.
A coluna “DiasUteis” é uma informação que esta atrelada a cada IdPeriodo. Em um periodo existe uma
certa quantidade de dias uteis para aquele periodos. No meu caso trasnformei essas    informações em
uma tabela de dias uteis e o IdPeriodo.
A coluna “Multiplicação” é a multiplicação dos DiasUteis por SomaProdutos.
A coluna “SomaMultiplicacao” é a soma total da coluna “Multiplicacao”.
A coluna “SomaDias” é a soma da coluna DiasUteis.
E a ultima coluna “Resultado” é a Divisão da coluna  “SomaMultiplicacao” por “SomaDias”.

Uma das vantagens da Windows Function é que podemos ter acesso aos detalhes de uma informação agrupada.
Mais informações Fabiano Amorim: http://blogs.solidq.com/fabianosqlserver/Post.aspx?ID=58

Vamos aos código (A parte boa….rs).
Primeiro crio as tabelas temporarias conforme arquivo .xls (É possivel fazer apenas com uma tabela de periodo,mas, depois da fejuca. Vamos que vamos). Crio a tabela de dias uteis e insiro as informações do meu arquivo .xls.
use tempdb
go
create table #tmp_produto_um(id_periodo int, id_produto int, valor decimal(19,2))
create table #tmp_produto_dois(id_periodo int, id_produto int, valor decimal(19,2))
create table #tmp_dias_uteis(id_periodo int, qtdeDias int)

insert into #tmp_produto_um(id_periodo,id_produto,valor) values(1,18,55.00),(2,18,44.00),(3,18,33.00),(4,18,22.00)
insert into #tmp_produto_dois(id_periodo,id_produto,valor) values(1,19,77.00),(2,19,66.00),(3,19,44.00),(4,19,33.00)
insert into #tmp_dias_uteis(id_periodo,qtdeDias)values(1,22),(2,21),(3,22),(4,23)

SELECT * FROM #tmp_produto_um
SELECT * FROM #tmp_produto_dois
SELECT * FROM #tmp_dias_uteis

 

 

 

Crio uma CTE com a soma dos Valores que no .xls é: SomaProdutos.A multiplicação que no .xls é:DiasUteis * SomaProdutos.

;WITH cte AS
(
SELECT    p.id_periodo                                AS IdPeriodo
        ,SUM(d.valor) + SUM(p.valor)                 AS ValorTotal
        ,u.qtdeDias                                    AS QtdeDias
        ,(SUM(d.valor) + SUM(p.valor)) * u.qtdeDias    AS ProdutVsDiasUteis
        FROM #tmp_produto_um p
        JOIN #tmp_produto_dois d
        ON p.id_periodo = d.id_periodo
        JOIN #tmp_dias_uteis u
        ON u.id_periodo = p.id_periodo
        GROUP BY p.id_periodo,u.qtdeDias
)
Abaixo realizo a query chamando a CTE e usando o SUM com o OVER() para que possa ser realizado a soma das colunas, sem a necessidade de agregação. E dentro da SubQuery crio a soma para ser usada como a coluna resultado. Código total abaixo:

;WITH cte AS
(
SELECT    p.id_periodo                                AS IdPeriodo
        ,SUM(d.valor) + SUM(p.valor)                 AS ValorTotal
        ,u.qtdeDias                                    AS QtdeDias
        ,(SUM(d.valor) + SUM(p.valor)) * u.qtdeDias    AS ProdutVsDiasUteis
        FROM #tmp_produto_um p
        JOIN #tmp_produto_dois d
        ON p.id_periodo = d.id_periodo
        JOIN #tmp_dias_uteis u
        ON u.id_periodo = p.id_periodo
        GROUP BY p.id_periodo,u.qtdeDias
)
SELECT  
        c.IdPeriodo,
        c.ValorTotal,
        c.QtdeDias,
        c.ProdutVsDiasUteis
        ,SUM(c.ProdutVsDiasUteis)        OVER()    AS SomaProdutVsDiasUteis
        ,SUM(c.QtdeDias)                OVER()    AS SomaTotalDias
        ,ROUND(D.SomaDiasUteis / D.SomaDias,2)  AS GeralCalculado
        FROM cte c
        JOIN (    SELECT    a.IdPeriodo
                        ,SUM(a.ProdutVsDiasUteis)        OVER()    AS SomaDiasUteis
                        ,SUM(a.QtdeDias)                OVER()    AS SomaDias
                FROM  cte a
                ) as D
        ON c.IdPeriodo = D.IdPeriodo

Como pode ser visto o resultado do SQLServer é o mesmo que o arquivo .xls que foi colocada no print anteriormente.
Resultado SQL Server:


Espero ter ajudado.
Abs a todos…e tenham uma ótima semana.


Funções de Ranking

No SQL Server 2005 apareceram as funes de ranqueamento. Essas funções nos ajudam a realizar algumas tarefas com mais facilidade que anteriormente(SQL 2000) .Você pode criar um numero incremental em uma consulta(simular a propriedade identity) ,criar funcionalidade de paginação e etc. Aqui mostrarei alguns exemplos onde essas funções possam ser aplicadas: A função ROW_NUMBER() acrescenta um inteiro incremental em uma consulta. Imagine que você precise montar uma consulta com o valor incremental e a nossa tabela não existe uma coluna identity(auto incremento), você pode usar a função ROW_NUMBER() para simular esse comportamento.

use tempdb
GO
if OBJECT_ID(‘dbo.tb_incrementa’,’U’)isnot null
drop table   dbo.tb_incrementa ;
create table dbo.tb_incrementa(cliente intnotnull,nome varchar(30)notnull)
INSERT INTO dbo.tb_incrementa(cliente,nome)
VALUES (10,’Kalen Delaney’),(15,’Paul Randal’),
(16,’Kimberly L. Tripp’),(19,’Itzik Ben Gan’),
(20,’Bill Gates’),(23,’Pinal’)

O select traz as informações dos clientes que tem código e nome,  o codigo do mesmo no incremental se nós quisessemos realizar uma consulta dando o valor incremental para os valores usaremos o ROW_NUMBER().

SELECT *  FROM dbo.tb_incrementa


Com a query abaixo possível criar um valor incremental para cada registro:
SELECT nome ASNomeCliente , ROW_NUMBER()OVER(ORDERBY cliente ASC)AS ValorInrementalFROM dbo.tb_incrementa:

Usando RANK e DENSE_RANK
Abaixo crio uma tabela chamada tb_corrida que armazena o nome de alguns pilotos e o tempo que os mesmos realizaram asprovas em uma competição.

if OBJECT_ID(‘dbo.tb_corrida’,’U’)is not  null
drop  table dbo.tb_corrida ;
create table dbo.tb_corrida
(idCorrida  intidentitynotnull, nomeCorredor varchar(30)notnull,
dataCorrida datenotnull, tempoCorrida timenotnull )

INSERT INTO dbo.tb_corrida(nomeCorredor,dataCorrida,tempoCorrida)
VALUES (‘Sebastian Vettel’,CURRENT_TIMESTAMP,’01:35:12:333′ ),
(‘Lewis Hamilton’,CURRENT_TIMESTAMP,’01:45:01:123′),
(‘Mark Webber’,CURRENT_TIMESTAMP,’01:45:00:128′),
(‘Felipe Massa’,CURRENT_TIMESTAMP,’01:59:15:123′),
(‘Rubens Barrichello’,CURRENT_TIMESTAMP,’01:59:15:123′),
(‘Vitaly Petrov’,CURRENT_TIMESTAMP,’02:15:16′),
(‘Sebastian Buemi’,CURRENT_TIMESTAMP,’02:15:16′),
(‘Jenson Button’,CURRENT_TIMESTAMP,’02:30:00′),
(‘Fernando Alonso’,CURRENT_TIMESTAMP,’02:31:56′)

Imagine que precisaremos criar uma query com o ranking de chegada dos corredores baseando-se no menor tempo de corrida poderiamos usar a função RANK() ou DENSE_RANK(). A única diferença entre elas que a RANK deixa um “buraco” para as informações que tem o mesmo valor. Você pode observar que Felipe Massa e Rubinho tem o mesmo tempo de conclusão da prova, fazendo os dois ficarem na mesma posição. A próxima classifição que deveria ser o “5” foi ignorado para o SQL Server. Quando a função DENSE_RANK() é utilizada esse “gap” desaparece. Como pode ser visto o SQL Server realiza o Rank em cima do tempo de concluso da prova.

SELECT nomeCorredor AS NomePiloto, tempoCorrida AS Tempo, RANK()OVER(ORDERBY tempoCorrida ASC)AS PosicaoRank, DENSE_RANK()OVER(ORDERBY tempoCorrida ASC)AS PosicaoDenseRank FROM dbo.tb_corrida

Um outro exemplo que pode ser feito montar o rank mundial dos corredores tendo como  parâmetro o número de vitórias/pontos do corredor. O corredor que tiver mais vitórias/ponto,  ser “top” no pódio. Esse exemplo também poderia também ser aplicado para criar a  tabela do campeonato brasileiro por exemplo. Abaixo crio a tabela tb_podio e populo com algumas informações ficticias.

if OBJECT_ID(‘dbo.tb_podio’,’U’)isnotnull
droptable dbo.tb_podio ;
createtable dbo.tb_podio(
idCorrida intidentitynotnull,
nomePiloto varchar(30)notnull,
Pais varchar(15)notnull,
totalPontos int,
Equipe varchar(40),
numeroVitorias int )
INSERT INTO dbo.tb_podio(nomePiloto,Pais,totalPontos,Equipe,numeroVitorias)
VALUES (‘Sebastian Vettel’,’ALE’,148,’RBR-Renault’, 4),
(‘Lewis Hamilton’,’ING’,85,’McLaren-Mercedes’,1),
(‘Mark Webber’,’AUS’,79,’RBR-Renault’,0),
(‘Rubens Barrichello’,’BRA’,2,’Williams-Cosworth’,0),
(‘Vitaly Petrov’,’ING’,21,’Renault-Lotus’,0),
(‘Sebastian Buemi’,’SUI’,7,’STR-Ferrari’,0),
(‘Jenson Button’,’ING’,76,’McLaren-Mercedes’,0),
(‘Fernando Alonso’,’ESP’,69,’Ferrari’,0 )

Abaixo a query e feita pelo o total de pontos acumulados pelos corredores. Montando o rank mundial por pontos.A query também poderia ser feita pelo numero de vitórias.

SELECT Equipe,nomePiloto as Piloto, numeroVitorias,TotalPontos ,
DENSE_RANK()OVER(ORDERBY totalPontos DESC)As Classificacao
FROM dbo.tb_podioORDERBYClassificacao

Usando o NTILE
O NTILE() usado para dividir um conjunto de resultados em grupos aproximadamente iguais. Imagine que você tem uma tabela de pedidos com o valor total dos pedidos. O departamento de negócios da empresa solicitou que você criasse uma query que trouxesse os produtos em grupo por valor.
O NTILE() recebe um inteiro como parâmetro, esse numero é usado para quebrar o total de registros em grupos. Quando o total de registros é divido em grupos pelo valor do parâmetros de entrada  do NTILE() o SQL Server incrementa a quantidade de registros da divisao(que sobraram) para o primeiros grupos. Por exemplo: Se temos 32 registros e dividimos ele em 3 grupos, o SQL Server ir criar 3 grupos com 10 registros. Com os dois registros restantes o SQL Server ir colocar um no primeiro grupo e outro no segundo. A query abaixo cria tr categorias para os produtos tendo como base o valor dos mesmos, so elas: Baixo, Medio e Alto.

if OBJECT_ID(‘dbo.tb_produtos’) is not null
 drop table dbo.tb_produtos ;
create table dbo.tb_produtos
(
codigo int identity not null,
descricao varchar(50) not null,
valor money not null
)
GO
INSERT INTO dbo.tb_produtos(descricao,valor)
VALUES (‘Lapis’,1.00), (‘Caneta’,1.50),(‘Celular’,130.00)
  ,(‘Livros PMO’,175.00), (‘Monitor’,450.00),(‘TV’,1200.00)
  ,(‘DVD’,450.00),(‘MP4’,250.00),(‘New Civic’,60000.00)
  ,(‘NoteBook’,2500.00),(‘Fogao’,176.00)
go
SELECT
  descricao AS Produto,
  valor  AS Valor,
 CASE NTILE(3) OVER(ORDER BY valor)
    WHEN 1 THEN ‘Baixo’
    WHEN 2 THEN ‘Médio’
    WHEN 3 THEN ‘Alto’
    ELSE ‘Sem Categoria’
 END AS DescricaoTitulo
FROM dbo.tb_produtos
ORDER BY valor;

Abs Galera. Por enquanto é só.

Removendo Cursor – Dica Rápida

Ola Galera, blz? Como o tempo está um pouco corrido essa vai ser uma dica rápida que pode ser usada no dia-a-dia.
Imaginem o cenário que é necessário criar uma string com diversos ID’s. E esses ID’s estão dentro de uma tabela. A idéia inicial seria realizar um loop para incrementar uma variavel e montar a nossa string.. Vamos ao exemplo:
O script abaixo cria uma tabela com os códigos do cliente que iremos usar para montar a nossa string.
use tempdb
go
if OBJECT_ID(‘dbo.tb_cliente’) is not null
drop table dbo.tb_cliente
go
create table dbo.tb_cliente(id int identity, codigoCliente int , nome varchar(50))
go
–Bloco que popula a tabela com informações dos clientes
set nocount on
declare @i int = 1
while @i <= 100
begin
insert into dbo.tb_cliente(codigoCliente,nome)values(@i,replicate(‘Thiago’,2))
set @i = @i + 1 *(2)
end
go

Declaramos as variaveis @count, @total para realizar o nosso loop. As variáveis @idCliente e @idClienteString serão usadas para armazenar os codigos concatenados. A tabela temporaria #CodigosCliente é usada para guardar as informações pertinentes ao predicado IN. O script abaixo preenche a tabela temporária com os registros que serão montados para o loop. Após a inserção, o total de registros e colocado em uma variável para que iniciemos a montagem da string.
declare @count int , @total int
declare @idCliente varchar(max), @idClienteString varchar(max)
create table #CodigosCliente(id int identity, codigoCliente int)
–Popula a temporaria com as informacoes que sera colocadas em uma string
insert into #CodigosCliente(codigoCliente)
select codigoCliente
from dbo.tb_cliente where codigoCliente between 10 and 50

set @idCliente = ‘ ‘
set @idClienteString = ‘ ‘
select  @total =count(id) from #CodigosCliente
set @count = 1
if @total > 0
begin
set @idClienteString = ‘codigoCliente IN ( ‘
end
else
begin
set @idClienteString = ‘codigoCliente IN (0 ‘
end
while @count <= @total
begin
if  @count > 1
begin
set @idClienteString = @idClienteString + ‘, ‘
end
select @idCliente=codigoCliente from #CodigosCliente where id=@count
set @idClienteString = @idClienteString + @idCliente
set @count = @count + 1
end
set @idClienteString = @idClienteString + ‘ )’
print @idClienteString
go
Após a execução do script acima, o SQL Server irá montar o predicado in com os valores, conforme imagem:

Conforme imagem acima, temos o resultado esperado, porém, operações linha-a-linha são mais custosas para o SQL Server. Nós poderíamos obter o mesmo resultado com o script abaixo:

declare @idCliente varchar(max )
declare @idClienteString varchar(max)
SET @idCliente =
SET @idClienteString =
SET @idClienteString = ‘codigoCliente IN (‘
SELECT @idCliente=@idCliente +‘,’+CONVERT(varchar(max),codigoCliente)from#CodigosCliente
SELECT @idCliente =substring(@idCliente,2,LEN(@idCliente))
SET @idClienteString = @idClienteString + @idCliente +‘)’
PRINT @idClienteString
Como podemos ver, temos o mesmo resultado com uma menor quantidade de linhas uma instrução única evitando o uso de um loop.

Créditos: Alexandre José Malachias….Valeu Boss

Constraints vs Query Performance

Neste post irei demonstrar a importancia de  criar constraints no SQL Server. Graças as Foreign keys e check constraints o optimizer pode criar planos mais eficientes para as querys. Dado o script abaixo da criação das tabelas temos a tabela de Customers e de Orders. Na modelagem proposta que dizer que um Customer pode ter uma ou mais Orders. Notem que o script de criacao da constraint fisica nessa tabela e feita na tabela “filha” no nosso caso a de Orders.
CREATE TABLEdbo.Customers (CustomerID INT  PRIMARYKEY)
CREATE TABLE dbo.Orders(OrderID INT  PRIMARYKEY,CustomerID INT NOT  NULL CONSTRAINT FKOrdersCustomers REFERENCES dbo.Customers(CustomerID)).
Executando a query abaixo, podemos notar que temos duas tabelas na consulta, mas se vc executar a query com o plano de execução o sql server uma apenas o operador fisico para acessar uma das tabelas. Esse compportamento acontece, pois, o otimizador sabe que não é necessario executar um teste de existencia dos registros, pois a FK garante que serao requeridas todas orders para referenciar com o customer. Conforme print abaixo:
SELECT O.OrderID,o.CustomerID
FROM dbo.Orders AS o
WHERE EXISTS(SELECT CustomerID FROM dbo.Customers AS c
WHERE c.CustomerID=o.CustomerID)

Agora o que aconteceria se desabilitarmos a constraint? Vamos aos testes (Amo muito tudo isso..rs)
ALTER TABLE dbo.Orders NOCHECK CONSTRAINT FKOrdersCustomers

Execute novamente  a query, pressione o CTRL+M antes para habilitar o Include Actual Execution Plan. Agora perceba que  o plano de execucao mudou, isso porque a constraint foi desabilitada e o SQL Server nao pode garantir que todas as Orders  tem um customer valido.
SELECT O.OrderID,o.CustomerID
FROM dbo.Orders AS o
WHERE EXISTS(SELECT CustomerID FROM dbo.Customers AS c WHERE c.CustomerID=o.CustomerID)

Para voltarmos ao plano anterior devemos habilitar novamente a constraint, conforme instrução abaixo:
ALTER TABLE dbo.Orders CHECK CONSTRAINT FKOrdersCustomers

Execute a query novamente e veja o plano de execucao. Note que o plano de execucao continua o mesmo de quando a constraint foi desabilitada.

Esse comportamento se da ao devido fato que: O SQL server nao pode garantir que nao foi inserido um registro nao valido enquanto a FK estava desabilitada. Vc pode verificar isso atraves da dmv sys.foreign_keys. A FK foi marcada como “nao confiavel“. Veja a query abaixo:
select name , is_not_trusted from sys.foreign_keys
Com o resultado da query acima  vc vera que a coluna is_not_trusted esta marcada com o valor 1  , indica que a FK nao e confiavel.
O que pode ser feito nesse caso e adicionar a opção WITH CHECK para a clausula alter table que habilita a constraint:

alter table dbo.Orders with check check constraint FKOrdersCustomers

Se a query for executada novamente vera que o plano de execucao sera o visto da primeira implementacao.

Se nesse meio tempo que a FK foi  desabilitada algum registro que nao condiz com a  implementacao da constraint fosse inserido . Uma mensagem de erro seria retornado para o SQL Server. Por exemplo se uma order fosse inserida com um CustomerID NULL.

Referencia: Microsoft Database Developer 2008 TK 70-433

Índices no SQL Server 2000

Esta semana(No ano de 2008) me deparei com um problema de otimização e então li muito a respeito. Hoje falarei de índices.
Antes de falarmos sobre os índices, falaremos como os dados no SQL Server são armazenados e como os mesmo são acessados.

Armazenamento de dados
Uma pilha é uma coleção de páginas de dados:
• Cada página contém 8 quilobytes (KB) de informações.
• Quando os registros são inseridos em uma página, e ela já está cheia, as páginas de dados são divididas.
• Um grupo de 8 páginas adjacentes é chamado de extensão.

Acesso aos Dados
O SQL Server acessa os dados de dois métodos.
• Examinando todas as páginas de dados das tabelas – chamado de exame de tabela. Ao executar um exame de tabela o SQL Server:
• Começa no inicio da tabela.
• Examina todos os registros da tabela, página a página.
• Extrai os registros que satisfazem os critérios da consulta.

• Usando índices. Ao usar um índice, o SQL Server:
• Percorre a estrutura da árvore do índice para localizar os registros solicitados pela consulta.
• Extrai apenas os registros necessários que satisfazem os critérios da consulta

Como Criar Índices?

Ao criar índices, leve em conta dois fatores: a natureza dos dados e a natureza das consultas realizada nas tabelas.
Natureza dos dados – Quando me refiro a natureza de dados, sempre levo em conta o tipo da coluna em que colocarei um índice, é recomendável que índices estejam em colunas do tipo: int, char, bigint, tinyint, smallint e datetime.
Natureza das consultas – As naturezas das consultas se referem em qual campo da minha tabela devo criar um índice, exemplo: Imagine um cenário que tenho que criar uma consulta que traga os pedidos emitidos por data de emissão e que a situação seja somente os pedidos liberados. Naturalmente na minha tabela de pedidos eu teria o campo data de emissão e situação do pedido. Essas são colunas aconselháveis para a criação de índices.
Os índices são úteis, porém consomem espaço em disco e acarretam custos de manutenção e sobrecarga. Não crie um índice que não será usado com freqüência.

Índice Clustered ou Agrupamento
Esse tipo de índice é útil para as colunas pesquisadas com freqüência ou em busca de chave de valores. Ao criar um índice desse tipo, considere as seguintes diretrizes:
• Cada tabela só pode ter um índice clustered.
• A ordem física dos registros da tabela e a ordem dos registros do índice são iguais. Primeiramente é aconselhável que seja criado o indice clustered antes do índice não clusterizado.
• Quando um registro é excluído, o espaço é restaurado e torna-se disponível para outro registro.
• Quando se cria uma coluna como PRIMARY KEY, automaticamente essa coluna torna-se um índice clustered.
• O tamanho médio de um índice clustered é aproximadamente 5% do tamanho da tabela. No entanto, esse tamanho varia dependendo do tamanho da coluna indexada.

Índice No-Clustered ou Sem Agrupamento
Um índice não clusterizado é eficiente quando os usuários precisam de vários critérios de pesquisa. Por exemplo, um vendedor pode pesquisar na tabela de pedidos pelo número do pedido, data de emissão, cliente e o representante deste cliente. Ao criar um índice não clusterizado, considere os seguintes fatos:
• A ordem das páginas no nível folha se um índice não clusterizado é diferente da ordem
• Pode existir até 249 índices não clusterizado por tabela.
• O SQL Server recria automaticamente os índices não clusterizados existentes quando ocorre uma das situações a seguir:
• Um índice clustered é criado.
• Um índice clustered é descartado.
• A opção DROP_EXISTING é usada para alterar as colunas que definem o índice de agrupamento.

Colunas que devem ser indexadas.
Crie índices em colunas pesquisadas com freqüências como:
• Chaves primárias (PK).
• Chaves externas (FK) ou colunas usadas frequentemente para unir tabelas.
• Colunas pesquisadas para a localização de faixa de valores de chave. (quando usamos a clausula IN, NOT IN, BETWEEN).
• Colunas acessadas na ordem de classificação (ORDER BY)
• Colunas usadas durante a agregação. (GROUP BY)

Colunas que NÃO devem ser indexadas.
Não referencie colunas que:
• Raramente são usadas em um consulta.
• Contenham poucos valores únicos. Por exemplo, um índice em uma coluna com dois valores, Masculino e feminino, retorna uma alta porcentagem de registros.
• Sejam definidas com os tipos de dados text, ntext, varchar e image. Não é possível indexar colunas com esses tipos de dados.

Criando índices.
Ao criar índice em uma tabela considere os fatos:
• Você deve ser proprietário da tabela.
• Quando se cria uma constraint do tipo PRIMARY KEY e UNIQUE, automaticamente o SQL Server cria índices clustered para elas.
• Você pode criar índices em VIEWS
• Você não pode criar índice em colunas que já existam os mesmos.
• Você pode criar índice na hora de criação de sua tabela.

Sintaxe:
CREATE NONCLUSTERED INDEX nomeDoIndice ON Tabela(CampoIndexado)
Apagando índice
Ao apagar um índice você deve levar em conta as seguintes diretrizes:
• Você não pode apagar os índices criados pelas restrições PRIMARY KEY e UNIQUE.
• Você não pode apagar os índices das tabelas do sistema.
• Você deve está no banco que reside o índice para apagá-lo.

Sintaxe:
DROP INDEX Tabela.NomeDoIndice

Na prática:
DROP INDEX DptoEmpresa.IdxEmpresaID

Até a próxima e espero que todos tenham gostado.
Obs: Esse post retirei de um site que havia publicado a muito tempo atras quando comecei a trabalhar com SQL Server, futuramente irei adicionar a questão de indicec om as features do SQL Server 2008