Domanda

Quando si recuperano valori da un DataRow è meglio usare il nome della colonna o l'indice della colonna?

Il nome della colonna è più leggibile e più facile da mantenere:

int price = (int)dr["Price"];

Mentre l'indice di colonna è solo più veloce (penso):

int price = (int)dr[3];

L'uso dei nomi delle colonne si spezzerebbe se decidessi di offuscare il database?

È stato utile?

Soluzione

In genere preferisco la leggibilità e la comprensione rispetto alla velocità. Vai con il nome. Potresti (dovresti) usare costanti di stringa che possono essere aggiornate in un unico posto se decidi di cambiare i nomi delle colonne del database.

Altri suggerimenti

L'accesso alle colonne / ai valori delle righe tramite i nomi delle colonne è migliore per la lettura umana e per la compatibilità futura (se in futuro qualcuno cambierà l'ordine o il conteggio delle colonne).

Accedere a colonne / valori di riga tramite gli indici delle colonne è migliore per le prestazioni.

Quindi, se vuoi cambiare un valore in una / due / ..... righe, i nomi delle colonne sono ok. Ma se vuoi cambiare un valore in migliaia di righe, dovresti usare l'indice di colonna calcolato dal nome della colonna:

int ndxMyColumn = table.Columns.IndexOf( "MyColumn" );
foreach(DataRow record in table.Rows ) {
    record[ndxMyColumn] = 15;
}

Completamente aggressivo con gli altri re. cerca leggibilità e manutenibilità sulla velocità. Avevo comunque un metodo generico che aveva bisogno di far passare le colonne con nome come parametri, quindi aveva senso capire quali fossero gli indici di colonna.

Nel benchmarking di seguito l'utilizzo dell'indice di colonna ha mostrato un notevole miglioramento, quindi se si tratta di un collo di bottiglia o di una parte critica del rendimento del codice, potrebbe essere utile.

L'output del codice seguente è:

515ms con ColumnIndex

1031ms con ColumnName

    static void Main(string[] args)
    {            
        DataTable dt = GetDataTable(10000, 500);
        string[] columnNames = GetColumnNames(dt);

        DateTime start = DateTime.Now;
        TestPerformance(dt, columnNames, true);

        TimeSpan ts = DateTime.Now.Subtract(start);
        Console.Write("{0}ms with ColumnIndex\r\n", ts.TotalMilliseconds);

        start = DateTime.Now;
        TestPerformance(dt, columnNames, false);
        ts = DateTime.Now.Subtract(start);
        Console.Write("{0}ms with ColumnName\r\n", ts.TotalMilliseconds);
    }

    private static DataTable GetDataTable(int rows, int columns)
    {
        DataTable dt = new DataTable();

        for (int j = 0; j < columns; j++)
        {
            dt.Columns.Add("Column" + j.ToString(), typeof(Double));
        }

        Random random = new Random(DateTime.Now.Millisecond);
        for (int i = 0; i < rows; i++)
        {
            object[] rowValues = new object[columns];

            for (int j = 0; j < columns; j++)
            {
                rowValues[j] = random.NextDouble();
            }

            dt.Rows.Add(rowValues);
        }

        return dt;
    }

    private static void TestPerformance(DataTable dt, string[] columnNames, bool useIndex)
    {
        object obj;
        DataRow row;

        for (int i =0; i < dt.Rows.Count; i++)
        {
            row = dt.Rows[i];

            for(int j = 0; j < dt.Columns.Count; j++)
            {
                if (useIndex)
                    obj = row[j];
                else
                    obj = row[columnNames[j]];
            }
        }
    }

    private static string[] GetColumnNames(DataTable dt)
    {
        string[] columnNames = new string[dt.Columns.Count];

        for (int j = 0; j < columnNames.Length; j++)
        {
            columnNames[j] = dt.Columns[j].ColumnName;
        }

        return columnNames;
    }

Penso che il nome della colonna sia il modo migliore per andare. È più facile determinare cosa stai tirando e l'ordine delle colonne è determinato dall'istruzione select che potrebbe cambiare in futuro. Potresti sostenere che anche il nome della colonna potrebbe cambiare, ma penso che questo sarebbe molto meno probabile.

EDIT:

In realtà se tu fossi davvero intenzionato ad usare gli indici di colonna, potresti creare costanti degli indici di colonna e nominare la costante il nome della colonna. Quindi:

PRIMARY_KEY_COLUMN_NAME_INDEX = 0

Ciò renderebbe almeno leggibile.

Dipende da cosa ti serve. Nel mio caso, ho avuto una situazione in cui la velocità era fondamentale in quanto eseguivo un'elaborazione intensa su migliaia di righe in un DataSet, quindi ho scelto di scrivere un pezzo di codice che memorizzava nella cache gli indici delle colonne per nome. Quindi, nel codice del ciclo ho usato gli indici memorizzati nella cache. Ciò ha dato un ragionevole aumento delle prestazioni rispetto all'uso diretto del nome della colonna.

Il tuo chilometraggio può variare, ovviamente. La mia situazione era piuttosto insolita e insolita, ma in quel caso ha funzionato piuttosto bene.

La mia opinione è che dovresti passare agli indici solo se hai profilato il tuo codice e mostrato come collo di bottiglia. Non penso che ciò accadrà.

La roba dei nomi è buona, fa sì che il nostro cervello limitato comprenda i problemi e crei collegamenti più facilmente. Ecco perché ci vengono dati nomi come Fred, Martin, Jamie, anziché Human [189333847], Human [138924342] e Human [239333546].

Se hai deciso di offuscare il database modificando i nomi delle colonne in futuro, puoi aliasare quelle colonne nella tua query per mantenere funzionale il codice dell'indicizzatore. Suggerisco di indicizzare per nome.

Vai con il nome, ottieni messaggi di errore migliori :)

Opto per le stringhe per facilità di lettura e manutenibilità. Uso costanti di stringa per definire i valori dei nomi delle colonne. Es:

public class ExampleDataColumns
{
    public const string ID = "example_id";
    public const string Name = "example_name";
    ....    
}

Quindi posso fare riferimento in un secondo momento in questo modo:

row[ExampleDataColumns.ID]

Usa i nomi di colonna per DataRow con lo stesso token che un RDBMS non otterrà velocità richiedendo ai programmatori di specificare l'indice di colonna in SQL. Ma puoi forse imitare il modo in cui opera un RDBMS quando emetti un'istruzione SELECT, all'interno di un motore RDBMS interroga l'indice di colonna / offset delle colonne specificate nella clausola SELECT prima di attraversare le righe, in modo che possa operare più velocemente.

Se vuoi davvero guadagnare velocità, non fallo nel modo const / enum (l'ordine delle colonne potrebbe cambiare nel tuo database o livello ORM). Fallo come suggerito da TcKs (prima del ciclo effettivo):

int ndxMyColumn = table.Columns.IndexOf( "MyColumn" );
foreach(DataRow record in table.Rows ) {
    record[ndxMyColumn] = 15;
}

per me, sto usando la riflessione (non sono sicuro che sia il modo corretto di nominare quello che faccio) per ottenere il nome colonnaColonna dalla tabella

no " hardcoding " è meglio

  int price = (int)dr[DatableVar.PriceColumn];
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top