2012-10-05 47 views
3

我正在制定一个优化我的数据库索引的过程,它需要我很长时间。所以我想确认是否可行?而且还没有做过其他事情想要得到它。优先从mysql数据库中删除重复的索引

  1. 我想读取所有表中的所有索引。
  2. 我想删除主键字段上的所有其他索引
  3. 做完上面的事情之后。仍被索引为唯一的字段。我想放弃所有其他指数
  4. 既不主要也不唯一的字段。我想只保留一个索引,并删除所有其他索引

我很好奇为什么MYSQL允许在主键字段上使用唯一索引?它可以使任何有用的区别?

问题: 我需要指导/查询/程序删除所有非有用的指标,在​​我以上4点

更新1中提到的层次:我会继续我的工作更新Here on SQLFiddle。目前它刚刚开始。但是,您可以在此链接上看到有四个字段和8个索引。我只想要其中的3个,并放弃所有其他人。我只需要第一,第三和第四。根据我上面的4点。

更新2:我得到了eggayal的出色答案。他给出的第一个链接是纯sql解决方案。我试过了Here at Link2。它给了我不想要的输出。 LINK2的输出可以通过寻找到Link1 here

希望的输出进行比较是

 
    COLUMN_NAMES REDUNDANT_INDEXES 
1 auth_id   `auth_id_3`,`auth_id_2`,`auth_id` 
2 id    `id_2`,`id_3` 
3 subject   `subject_1` 

故障查询的个输出在Link2

ROW1:AUTH_ID未示出作为冗余索引,因为它与相同字段上的唯一密钥auth_id_4无关(比较)。但我需要它,因为在同一列具有唯一索引以及

行2我不需要这个指数:我想说的时候存在一些列

主键 索引的所有其他指数冗余ROW3:好吧

+0

你能举一个你正在谈论的例子吗?例如'ExampleTableName中的show index' – FoolishSeth

+0

是的,我将更新sqlfiddle链接。和你说的一样。 'show idex from',然后在丢弃之前保存这些索引 – Sami

+1

仅给定数据库模式,没有单一的“最佳索引策略”。事实上,在不知道要在数据上执行的查询的情况下参考索引是没有意义的。索引是一种折衷:它们减慢了写入操作(插入/更新),但加快了读取操作(选择);因此,对于您而言,“最佳”索引策略将取决于应用程序执行的读写比例。它还取决于实际的查询,因为不同的查询将受益于不同的索引。 – eggyal

回答

2

我在c#中做了一个应用程序。它删除重复索引根据您的优先级,希望它会帮助

它可能需要很大的改进,但我知道的是......它并不只是删除那些涉及主要(复合)和外键一时间(这不应该是平时好办法)

Here is download link for complete application with source

以下是上面的链接的主文件

using System; 
using System.Data; 
using MySql.Data.MySqlClient; 
using System.Collections.Generic; 

namespace duplicateIndexRemover 
{ 
public class duplicateIndexRemover 
{ 

    static List<string> toDrop; 
    public string main(System.Windows.Forms.DataGridView dgv, System.Windows.Forms.DataGridView dgv1, string dbName) 
    {    
     try 
     { 
      toDrop = new List<string>(); 
      List<table> tbs = new List<table>(); 
      DataTable dt1 = new DataTable(); 
      string cnStr = "SERVER=localhost;DATABASE=" + dbName + ";UID=root;"; 
      MySqlConnection conn = new MySqlConnection(cnStr); 
      MySqlCommand cmd = conn.CreateCommand(); 
      cmd.CommandText = @"SELECT Table_Name,Column_Name,Index_Name,NON_UNIQUE 
      FROM information_schema.STATISTICS 
      WHERE table_schema = '" + dbName + "' order by Table_Name,Column_Name,Index_Name"; 
      MySqlDataAdapter adp = new MySqlDataAdapter(cmd); 
      DataTable dt = new DataTable(); 
      adp.Fill(dt); 
      dgv.DataSource = dt; 
      for (int i = 0; i < dt.Columns.Count - 1; i++) 
       dt1.Columns.Add(dt.Columns[i].ColumnName); 

      table tb = new table(); 
      column cl = new column(); 
      index dx = new index(); 
      tb.nam = dt.Rows[0][0].ToString(); 
      cl = addColumn(dt, tb, 0); 
      tbs.Add(tb); 

      for (int i = 1; i < dt.Rows.Count; i++) 
      { 
       if (tb.nam != dt.Rows[i][0].ToString()) 
       { 
        // 1st column of (current) t_th table 
        tb = new table(); 
        tb.nam = dt.Rows[i][0].ToString(); 
        cl = addColumn(dt, tb, i); 
        tbs.Add(tb); 
       } 
       else 
       { 
        if (cl.nam != dt.Rows[i][1].ToString()) 
         cl = addColumn(dt, tb, i); 
        else 
        { 

         // Duplicate Indices 
         // But this one may be primary/unique key 
         // Then it would not be good to make a drop statement for this index here 
         // It may be improvable, but i can not apply as well condition here if it is not primary key 
         addIndex(dt, cl, i); 
        } 
       } 
      } 
      makeDropStatements(tbs, dt1); 

      dgv1.DataSource = dt1; 
      cmd.Connection.Open(); 
      for (int i = 0; i < toDrop.Count; i++) 
      { 
       cmd.CommandText = toDrop[i]; 
       try 
       { 
        cmd.ExecuteScalar(); 
       } 
       catch//(Exception ex) 
       { 
        //System.Windows.Forms.MessageBox.Show("Table : " + dt1.Rows[i][0] + " Column : " + dt1.Rows[i][1] + "\n\n" + ex.Message); 
       } 
      } 

      cmd.CommandText = @"select table_name from information_schema.STATISTICS 
      WHERE table_schema = '" + dbName + "' group by table_name,column_name"; 
      DataTable dg = new DataTable(); 
      adp.Fill(dg); 

      string msg = " Total Number of Indices : " + dt.Rows.Count; 
      msg += "\t Droppable Indices : " + toDrop.Count; 
      msg += "\t Total Number of Indexed Columns : " + dg.Rows.Count; 
      return msg; 
     } 
     catch (Exception ex) 
     { 
      System.Windows.Forms.MessageBox.Show(ex.Message); 
      return ex.Message; 
     } 
    } 

    private static column addColumn(DataTable dt, table tb, int i) 
    { 
     column cl = new column(); 
     // 1st index of i_th column of t_th table 
     cl.nam = dt.Rows[i][1].ToString(); 
     addIndex(dt, cl, i); 
     tb.cols.Add(cl); 
     return cl; 
    } 

    private static void addIndex(DataTable dt, column cl, int i) 
    { 
     index dx = new index(); 
     dx.nam = dt.Rows[i][2].ToString(); 
     dx.non_unique = Convert.ToBoolean(dt.Rows[i][3]); 
     cl.indices.Add(dx); 
    } 


    private static void makeDropStatements(List<table> tbs, DataTable dt1) 
    { 
     bool chekd; 
     List<index> temp; 
     for (int t = 0; t < tbs.Count; t++) 
     {     
      for (int i = 0; i < tbs[t].cols.Count; i++) 
      {      
       temp = tbs[t].cols[i].indices; 
       if (temp.Count > 1) 
       { 

        chekd = false; 
        for (int j = 0; j < temp.Count; j++) 
        { 
         if (temp[j].nam == "PRIMARY") 
         { 
          getToDropIndices(tbs[t].nam, tbs[t].cols[i].nam, temp, j, dt1); 
          chekd = true; 
          break; 
         } 
        } 
        if (!chekd) 
        { 
         for (int j = 0; j < temp.Count; j++) 
         { 
          if (!temp[j].non_unique) 
          { 
           getToDropIndices(tbs[t].nam, tbs[t].cols[i].nam, temp, j, dt1); 
           chekd = true; 
           break; 
          } 
         } 
        } 
        if (!chekd) 
        { 
         getToDropIndices(tbs[t].nam, tbs[t].cols[i].nam, temp, 0, dt1); 
         chekd = true; 
         break; 
        } 
       } 
      } 
     } 
    } 

    private static void getToDropIndices(string tbl, string col, List<index> sublist, int nt, DataTable dt1) 
    { 
     for (int j = 0; j < nt; j++) 
     { 
      toDrop.Add("alter table `" + tbl + "` drop index " + sublist[j].nam); 
      dt1.Rows.Add(dt1.NewRow()); 
      int r = dt1.Rows.Count - 1; 
      dt1.Rows[r][0] = tbl; 
      dt1.Rows[r][1] = col; 
      dt1.Rows[r][2] = sublist[j].nam; 
     } 
     for (int j = nt + 1; j < sublist.Count; j++) 
     { 
      toDrop.Add("alter table `" + tbl + "` drop index " + sublist[j].nam); 
      dt1.Rows.Add(dt1.NewRow()); 
      int r = dt1.Rows.Count - 1; 
      dt1.Rows[r][0] = tbl; 
      dt1.Rows[r][1] = col; 
      dt1.Rows[r][2] = sublist[j].nam; 
     } 
    } 
} 

public class table 
{ 
    public List<column> cols =new List<column>(); 
    public string nam = ""; 
} 

public class column 
{ 
    public List<index> indices = new List<index>(); 
    public string nam = ""; 
} 

public class index 
{ 
    public string nam = ""; 
    public bool non_unique; 
} 
} 

你可以忽略/删除GridView的它们只是展示你的指数。你只需要调用主函数

+0

非常感谢你的帮助。其优秀的soltuion – Sami

+0

欢迎您.. :) – 2012-10-30 12:57:02

1

根据我看到的链接那里似乎是一个多余的数量指标这样的:

KEY `auth_id_2` (`auth_id`), 
KEY `auth_id_4` (`auth_id`), 
KEY `auth_id_5` (`auth_id`), 
KEY `auth_id_6` (`auth_id`) 

我想也许他们是建于不同的方式。例如,一个可能是BTREE,另一个可能是HASH,这可能有助于某种目的。但是根据SHOW,它们都是一样的。删除额外的相同的不应该是一个问题。

是有目的的,以具有例如,所有这三个,但:

KEY `articleid` (`artid`), 
KEY `artSub` (`artSub`), 
KEY `comments_ibfk_3` (`artSub`,`artid`) 

建立在两列索引是不一定相同的上一个建设两个单独的索引。

+0

看到投票感到惊讶。在发布之前,我已经尽力使这个问题非常清楚。但是我需要被告知什么是如此令人困惑?我会尽力说清楚。但真正的问题是如何删除多个指数与我在前4点提到的优先 – Sami

2

Roland Bouman在这个主题上写了一个blog article,展示了一个纯粹的SQL解决方案。

quick search on Google也搅起:

+0

感谢eggayal。你确定它在我的问题中的作用与我需要的相同。第一个链接似乎很有说服力,我将查看所有内容。感谢您的帮助+1。希望这将是可接受的和所需的解决方案准确或几乎根据问题:) – Sami

+0

@Sami:所有这些解决方案都是为了响应Peter Zaitsev的文章[重复索引和冗余索引](http://www.mysqlperformanceblog 。com/2006/08/17/duplicate-indexes-and-redundant-indexes /),Roland Bouman在他的博客中提到。正如你将会看到的,彼得正在记录你上面描述的问题;因此,虽然我没有验证每个解决方案,但他们应该尝试完全满足您的需求。 – eggyal

+0

加上感谢有关谷歌搜索的指导。而information_scema.statisitics是非常非常有用的东西,我今天从你的第一个链接凸现出来 – Sami