2012-10-05 48 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