Há a necessidade da utilização dos índices na estrutura das tabelas de nossa base de dados, pois as buscas são realizadas de forma mais satisfatória em termos de desempenho para a aplicação. Para entendermos isso na prática, vamos criar uma aplicação simples de CRUD.

Por onde começar?

Uma das dúvidas frequentes que nos ocorre é por onde começar a desenvolver o nosso projeto. Quanto a isso, a resposta é: depende. Depende do que vocês estejam mais habituados a trabalhar, se é com a base de dados propriamente dita ou se é pela aplicação (com a criação de telas, por exemplo) e a codificação. Aqui, começaremos com a criação da base de dados, já que é o ponto crucial para o entendimento dos índices.

O nosso projeto será uma base para um sistema acadêmico, onde o administrador será capaz de fazer as operações básicas do sistema, como inserções de alunos, atualizações das informações, exclusão e principalmente, pesquisas por alunos. Já o aluno poderá apenas mudar a sua senha de acesso.

Criando a base de dados do zero

Para começar, vamos abrir o nosso SQL Server e criar a base de dados que será utilizada para nossa aplicação. Nossa base será composta apenas de uma tabela: Usuarios. Aqui estamos utilizando a versão 2012, mas fiquem a vontade para trabalhar com a versão que lhes for melhor. Após abrir a aplicação, criemos uma nova database, chamada de banco_teste e em seguida, abram uma nova aba para digitar as nossas queries. Estas seguem de acordo com a Listagem 1.

Listagem 1. Criação da tabela usuario

CREATE TABLE [dbo].[usuario](
                  [idUsuario] [int] IDENTITY(1,1) NOT NULL,
                  [nome] [varchar](50) NOT NULL,
                  [email] [varchar](50) NOT NULL,
                  [telefone] [varchar](13) NULL,
                  [senha] [varchar](6) NOT NULL,
                  [login] [varchar](10) NOT NULL,
                  [seAdministrador] [bit] NULL,
   CONSTRAINT [PK_usuario] PRIMARY KEY CLUSTERED 
  (
                  [idUsuario] ASC
  )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  ) ON [PRIMARY]
  GO
   
  ALTER TABLE [dbo].[usuario] ADD  CONSTRAINT [DF_usuario_seAdministrador]  DEFAULT ((0)) FOR [seAdministrador]
  GO
   
  CREATE NONCLUSTERED INDEX [IX_nomeUsuario]
      ON [dbo].[usuario]([nome] ASC);
  GO

Para criarmos os índices através do management do SQLServer, procederemos de acordo com as Figuras 1 a 4. Primeiro abriremos a nossa tabela em forma de Design. Clicamos com o botão direito do mouse em cima do nome da nossa base de dados e selecionamos a opção Design. Após a tela ter sido aberta com os campos que já criamos, veremos no canto superior esquerdo o ícone de uma chave sobre uma tabela. Este é o ícone “Manage indexes and Keys” apresentado na Figura 2. Clique nele para chegar a outra tela, onde deve-se clicar em “Add” para que possamos criar um novo índice. Serão apresentadas diversas informações nesta tela, algumas que podemos alterar, como o nome, e outras que não, assim como o índice, pois como já havíamos criado uma chave primária, esta por definição já seria a clusterizada. Então vamos criar as não clusterizadas, de acordo com a Figura 3. Após criar os índices que precisamos, podemos visualizá-los na pasta indexes, que é apresentada quando clicamos no sinal de “+”, situado do lado da nossa tabela criada, como apresentado na Figura 4.

Figura 1. Abrindo a tabela em forma de Design.

Figura 2. Selecionando o ícone de gerenciador de chaves e Índices.

Figura 3.Criação dos índices não clusterizados.

Figura 4. Visualização dos índices criados.

Como podemos observar na criação de nossa tabela, ela recebe um índice clusterizado para a chave primária e este é o que identifica a sequência lógica com que os dados serão armazenados na tabela. Um outro ponto que podemos ressaltar aqui é com relação ao índice não clusterizado que criamos na tabela de usuário. Estes índices serão armazenados numa estrutura a parte das tabelas nas quais se encontram, mantendo uma ordem referencial para a própria tabela. Sabendo quais colunas na tabela podemos usá-las como índices não clusterizados, facilitando e muito na hora de realizarmos uma busca pelo nome do aluno, por exemplo. A grande problemática é justamente sabermos quais são estas colunas no decorrer do desenvolvimento de um sistema. Percebam que não foi criada na Listagem 1 um índice não clusterizado para a coluna de e-mail, pois caso quiséssemos buscar algum usuário (levando-se em consideração uma grande quantidade de usuários registrados), a nossa busca pode levar mais tempo que uma busca sendo realizada pelo nome do usuário.

Agora que temos nossa base de dados criada e com os índices que poderão ser utilizados para a realização das buscas, começaremos a trabalhar no visual studio (usaremos o Visual studio 2013) para criar a nossa aplicação.

Tela de login do sistema

Antes de mais nada, precisamos fazer a conexão do visual studio com a base de dados que criamos no SQL Server, então para isso vamos até a aba SQL Server Object Explorer, como mostrado na Figura 5. Caso não esteja vendo esta aba nas suas configurações, basta acessar através da guia VIEW, como apresentada na Figura 6. Assim que visualizado o SQL Server Object, clicamos com o botão direito do mouse sobre o link “Add SQL Server” e na próxima tela que aparecer entre com o Server name que foi gravado na sua máquina para acessar o SQL Server. Após isso, a sua conexão estará concluída e então você seleciona o database que foi criado. Após selecioná-lo na aba de propriedades, procuraremos pela connection string e então, selecionamos o seu conteúdo, como segue nas Figuras 7 e 8.

Figura 5. Acessando o SQL Server pelo Visual Studio.

Figura 6. Acessando o SQL Server Object pela guia VIEW.

Figura 7. Selecionando o banco que será utilizado.

Figura 8. Selecionando o conteúdo da connection string.

Agora que possuímos a string de conexão, vamos criar uma classe chamada acessoDados. Esta classe será responsável por conter toda a lógica do nosso CRUD, além de nossas configurações de acesso a base de dados.

Começaremos a nossa codificação da seguinte forma: como esta aplicação é apenas para demonstração, estão sendo utilizadas técnicas simples apenas para manter o entendimento do projeto, o que mixou um pouco de banco de dados e desenvolvimento C#. O nosso código referente a classe acessoDados.cs ficará de acordo com o exposto na Listagem 2.

Listagem 2. Código referente a classe de acesso a dados.


  namespace AcessoSistema
  {
      public class acessoDados
      {
       SqlConnectionconn = null;
       private string strConn = @"Data Source=EDSON; InitialCatalog=banco_teste;
       Integrated Security=True; Connect Timeout=15;   
       Encrypt=False;TrustServerCertificate=False";
       private string strSQL = string.Empty;
   
        public SqlConnection conectar()
          {
            conn = new SqlConnection(strConn);
   
             try
              {
                 conn.Open();
   
              }catch(Exception e){
                 conn = null;
              }
   
              return conn;
          }
   
          public bool insert(ArrayListarrayInsere)
          {
           strSQL = "insertintousuariovalues ( @nome, @email, @telefone, @senha, @login,   
            @seAdministrador)";
            SqlCommandcmd = null;
   
            if (this.conectar() != null)
              {
               try
                  {
                    cmd = new SqlCommand(strSQL, conn);
                    cmd.Parameters.Add(new SqlParameter("@nome", arrayInsere[0]));
                    cmd.Parameters.Add(new SqlParameter("@email", arrayInsere[1]));
                    cmd.Parameters.Add(new SqlParameter("@telefone", arrayInsere[2]));
                    cmd.Parameters.Add(new SqlParameter("@senha", arrayInsere[3]));
                    cmd.Parameters.Add(new SqlParameter("@login", arrayInsere[4]));
                    cmd.Parameters.Add(new SqlParameter("@seAdministrador", arrayInsere[5]));
   
                    cmd.ExecuteNonQuery();
   
                    return true;
                  }
                  catch (SqlException e)
                  {
                    throw e;
                  }
              }
             else
              {
                return false;
              }
          }
   
   
            public bool edit(ArrayListarrayEditar)
          {
             strSQL = "updateusuario set nome = @nome, email = @email, 
              telefone = @telefone, senha = @senha, login = @login, 
              seAdministrador = @seAdministradorwhereidUsuario = @idUsuario"; 
              SqlCommandcmd = null;
   
              if (this.conectar() != null)
              {
   
                 try
                  {
                     cmd = new SqlCommand(strSQL, conn);
   
                     cmd.Parameters.Add(new SqlParameter("@idUsuario", arrayEditar[0]));
                     cmd.Parameters.Add(new SqlParameter("@nome", arrayEditar[1]));
                     cmd.Parameters.Add(new SqlParameter("@email", arrayEditar[2]));
                     cmd.Parameters.Add(new SqlParameter("@telefone", arrayEditar[3]));
                     cmd.Parameters.Add(new SqlParameter("@senha", arrayEditar[4]));
                     cmd.Parameters.Add(new SqlParameter("@login", arrayEditar[5]));
                     cmd.Parameters.Add(new SqlParameter("@seAdministrador", arrayEditar[6]));
   
                     cmd.ExecuteNonQuery();
   
                     return true;
                  }
                     catch (SqlException e)
                  {
                     throw e;
                  }
   
              }
               else
              {
                return false;
              }
   
          }
   
            public bool delete(intidUsuario)
          {
              strSQL = "delete fromusuariowhereidUsuario = @idUsuario";
              SqlCommandcmd = null;
   
              if (this.conectar() != null)
              {
                try
                  {
                     cmd = new SqlCommand(strSQL, conn);
                     cmd.Parameters.AddWithValue("@idUsuario", idUsuario);
                     cmd.ExecuteNonQuery();
   
                     return true;
                  }
                  catch (SqlException e)
                  {
                     throw e;
                  }
              }
               else
              {
                return false;
              }
          }
   
   
          public DataTableListaGrid()
          {
             strSQL = "selectidUsuario as Código, nome, email, telefone, senha, 
             login, seAdministrador as Administrador fromusuario";
             SqlCommandcmd = null;
             DataTabledt = null;
   
             if (this.conectar() != null)
              {
                try
                  {
                    cmd = new SqlCommand(strSQL, conn);
   
                    SqlDataAdapteradt = new SqlDataAdapter(cmd);
                    dt = new DataTable();
                    adt.Fill(dt);
   
                    return dt;
                  }
                    catch (SqlException e)
                  {
                    throw e;
                  }
              }
               else
              {
                 return null;
              }
          }
   
            public DataTable Pesquisar(string pesquisa, stringparametro)
          {
              this.strSQL = pesquisa;
              SqlCommandcmd = null;
              DataTabledt = null;
   
              if (this.conectar() != null)
              {
                 try
                  {
                     cmd = new SqlCommand(strSQL, conn);
                     cmd.Parameters.Add(new SqlParameter("@nome", parametro));
   
                     SqlDataAdapteradt = new SqlDataAdapter(cmd);
                     dt = new DataTable();
                     adt.Fill(dt);
   
                     return dt;
                  }
                     catch (SqlException e)
                  {
                     throw e;
                  }
              }
                     else
              {
                     return null;
              }
          }
      }
  }

Nesta classe estão contidos os métodos que utilizaremos mais corriqueiramente como inclusão, edição, etc. Agora para visualizarmos a tela funcionando, devemos chamá-la pela classe principal do nosso projeto, que é a classe program.cs. O código dessa tela está sendo apresentado na Listagem 3.

Listagem 3. Classe program.cs.


  namespaceAcessoSistema
  {
    staticclassProgram
      {
          [STAThread]
          staticvoidMain()
          {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
   
            telaLoginfrmLogin = new telaLogin();
            frmLogin.ShowDialog();
   
            if (frmLogin.logou)
              {
                Application.Run(new telaPrincipal());
              }
          }
      }
  }

Agora que temos a classe de acesso a dados e a instanciação do primeiro formulário realizada na classe principal, iremos trabalhar na codificação da nossa tela de login propriamente dito. O código será basicamente de acordo com a da Listagem 4.

Listagem 4. Criação da classe telaLogin.


  namespace AcessoSistema
  {
     public partial class telaLogin : Form
      {
         public bool logou = false;
   
         public void acessarSistema()
          {
                  // Instanciando a classe de acesso a dados e em seguida criando uma 
               // nova instância do SQLConnection.
               acessoDados ad = new acessoDados();
               SqlConnection conecta = ad.conectar();
   
               stringusuario, senha;
               bool perfil = false;
               intid_usuario = 0;
   
               try
                  {
                     usuario = txtLogin.Text;
                     senha = txtSenha.Text;
   
                     if (usuario != "" && senha != "")
                      {
                          stringstrSQL = "select * fromusuariowherelogin = @loginand senha = @senha";
   
                          try
                         {
                             if (ad.conectar() != null)
                             {
                                SqlCommandcmd = new SqlCommand(strSQL, conecta);
                                cmd.Parameters.Add("@login", SqlDbType.VarChar).Value = usuario;
                                cmd.Parameters.Add("@senha", SqlDbType.VarChar).Value = senha;
   
                                 // Utilizando o SQLDataReader para buscar as informações necessárias para o sistema.
                                SqlDataReaderdr = cmd.ExecuteReader();
                                if (dr.Read())
                                 {
                                    id_usuario = Convert.ToInt32(dr["idUsuario"]);
                                    perfil = (bool)dr["seAdministrador"];
                                    usuario = dr["login"].ToString();
                                    senha = dr["senha"].ToString();
   
                                    logou = true;
   
                                    telaPrincipaltp = new telaPrincipal();
                                    tp.perfilAdm = perfil;
                                     tp.id = id_usuario;
                                    tp.ShowDialog();
   
                                    this.Dispose();
                                 }
                                 else
                                 {
                                    MessageBox.Show("Erro ao logar no sistema");
                                    logou = false;
                                 }
   
                                 dr.Close();          
                             }                           
                         }
                         catch (Exception e)
                         {
                            MessageBox.Show("Nada funcionando!!  " +e);
                         }                        
                      }
                      else
                      {
                       MessageBox.Show("Os campos devem ser preenchidos");
                      }
                  }
                   catch (Exception e)
                  {
                  MessageBox.Show(e + "Falhas do sistema");
                  }
              }
   
               private void btnAcessar_Click(objectsender, EventArgs e)
          {
           acessarSistema();
          }
   
              private void btnCancelar_Click(objectsender, EventArgs e)
          {
            Application.Exit();
          }
      }
  }

Com a classe de login criada, devemos testar o código e a conexão a base para ver se está tudo ok. Para isso, adicionem algumas informações na tabela que criamos e realizem os testes. Agora criaremos a nossa tela principal, que contará com um pouco a mais de trabalho a ser realizado. O código seguirá de acordo com o da Listagem 5.

Listagem 5.Classe da telaPrincipal.


  namespace AcessoSistema
  {
   public partial class telaPrincipal : Form
      {
        public bool perfilAdm;
         public int id;
   
          public telaPrincipal()
          {
           InitializeComponent();            
            tvcGuias.SelectTab(3);
          }
   
          private void btnEditar_Click(objectsender, EventArgs e)
          {
            acessoDadosobj = new acessoDados();
            ArrayListarray = new ArrayList();
   
            array.Add(txtIdUsuario.Text);
   
            txtIdUsuario.Enabled = false;
   
            array.Add(txtNome.Text);
            array.Add(txtEmail.Text);
            array.Add(txtTelefone.Text);
            array.Add(txtSenha.Text);
            array.Add(txtLogin.Text);
   
            if (cbAdministrador.Checked == true)
              {
                cbAdministrador.Checked = true;
              }
            else
              {
                 cbAdministrador.Checked = false;
              }
   
            array.Add(cbAdministrador.Checked);
   
            if (obj.edit(array))
              {
                  MessageBox.Show("Informações atualizadas com sucesso");
              }
               else
              {
                MessageBox.Show("Não foi possível atualizar os dados!");
              }
   
              if (tvcGuias.TabIndex == 3)
              {
                tvcGuias.SelectTab(3);
              }
               else
              {
                tvcGuias.SelectTab(1);
              }
          }
   
            private void dgvDados_Enter(objectsender, EventArgs e)
          {
            acessoDadosobj = new acessoDados();
   
            dgvDados.DataSource = obj.ListaGrid();
          }
   
           private void tvcGuias_Click(objectsender, EventArgs e)
          {
            dgvDados_Enter(e, e);
          }
   
           private void dgvDados_CellMouseDoubleClick(objectsender, DataGridViewCellMouseEventArgs e)
          {
              // Pegando as informações da linha da grid para passar para os campos de edição.
              DataGridViewRowlinhaAtual = new DataGridViewRow();
              linhaAtual = dgvDados.CurrentRow;
   
              if ((int)linhaAtual.Cells[0].Value == id)
              {
                desabilitarEHabilitaBotoes();
   
                txtIdUsuario.Text = linhaAtual.Cells[0].Value.ToString();
                txtNome.Text = linhaAtual.Cells[1].Value.ToString();
                txtEmail.Text = linhaAtual.Cells[2].Value.ToString();
                txtTelefone.Text = linhaAtual.Cells[3].Value.ToString();
                txtSenha.Text = linhaAtual.Cells[4].Value.ToString();
                txtLogin.Text = linhaAtual.Cells[5].Value.ToString();
                cbAdministrador.Checked = (bool)linhaAtual.Cells[6].Value;
   
                  // Habilitando a aba de edição.
                if (perfilAdm != true)
                  {
                    tvcGuias.SelectTab(0);
                     textBoxDesabilitados();
                  }
                  else
                  {
                     tvcGuias.SelectTab(1);
                     txtIdUsuario.Enabled = false;
                     txtNome.Enabled = true;
                     txtEmail.Enabled = true;
                     txtTelefone.Enabled = true;
                     txtSenha.Enabled = true;
                     txtLogin.Enabled = true;
                     cbAdministrador.Enabled = true;
                     txtPesquisa.Enabled = false;
                  }
              }
              else
              {
                     MessageBox.Show("Você não pode alterar esse registro. Apenas o seu registro pode ser alterado por você.");
              }
          }
   
           // No método Load é que carregamos informações que precisam ser geradas 
          // assim que os formulários forem abertos.
          private void telaPrincipal_Load(objectsender, EventArgs e)
          {
             dgvDados_Enter(e, e);
   
              // Habilitando a aba de listagem                    
              if (perfilAdm != true)
              {
                  // Removendo tabs que não serão usadas pelo usuário comum
                  tvcGuias.TabPages.Remove(tbpCadastro);
                  tvcGuias.TabPages.Remove(tbpExcluir);
   
                  // Visualizando a grade de informações
                  tvcGuias.SelectTab(1);
                  textBoxDesabilitados();
              }
              else
              {
                  tvcGuias.SelectTab(0);
                  textBoxDesabilitados();
              }
          }
   
          private void tvcGuias_SelectedIndexChanged(objectsender, EventArgs e)
          {
           if (tvcGuias.SelectedIndex == 0)
              {
                  tvcGuias.SelectTab(0);
                  textBoxDesabilitados();
                  desabilitarEHabilitaBotoes();             
              }
             else if (tvcGuias.SelectedIndex == 1)
              {
                  tvcGuias.SelectTab(1); 
                  textBoxDesabilitados();
              }
              else if (tvcGuias.SelectedIndex == 2)
              {
                  tvcGuias.SelectTab(2);
                  textBoxDesabilitados();
              }
               else
              {
                  tvcGuias.SelectTab(3); 
                  txtPesquisa.Enabled = true;
                  textBoxDesabilitados();
                  desabilitarEHabilitaBotoes();
              }
          }      
      }
  }

Após toda a codificação ter sido realizada, podemos testar o nosso projeto fazendo novas inserções, edições, exclusões e pesquisas nos registros salvos em nossa base de dados e ainda melhor, tendo uma base com índices não clusterizados para melhorar nossas buscas.

Para não alongar demais o artigo, alguns recursos das classes foram omitidos, mas o código fonte seguirá para download e com isso, vocês poderão tirar suas dúvidas.

Até a próxima.