È ansible selezionare * l’utilizzo mai giustificato?

Ho sempre predicato ai miei sviluppatori che SELECT * è malvagio e dovrebbe essere evitato come la peste.

Ci sono casi in cui può essere giustificato?

Non sto parlando di COUNT(*) , che la maggior parte degli ottimizzatori può capire.

modificare

Sto parlando del codice di produzione.

E un grande esempio che ho visto di questa ctriggers pratica era un’applicazione legacy di asp che utilizzava select * in una stored procedure e usava ADO per scorrere i record restituiti, ma otteneva le colonne per indice. Puoi immaginare cosa è successo quando un nuovo campo è stato aggiunto da qualche altra parte oltre la fine dell’elenco dei campi.

Sono abbastanza contento di usare * nei trigger di controllo.

In tal caso, può effettivamente rivelarsi un vantaggio poiché assicurerà che se si aggiungono colonne aggiuntive alla tabella di base, si verificherà un errore in modo che non possa essere dimenticato di occuparsi di questo nella struttura del trigger e / o della tabella di controllo.

(Come dotjoe ) Sono anche felice di utilizzarlo nelle tabelle derivate e nelle espressioni delle tabelle delle colonne. Anche se lo faccio abitualmente al contrario.

 WITH t AS (SELECT *, ROW_NUMBER() OVER (ORDER BY a) AS RN FROM foo) SELECT a, b, c, RN FROM t; 

Conosco principalmente SQL Server e almeno l’ottimizzatore non ha problemi nel riconoscere che saranno richieste solo le colonne a,b,c e l’uso di * nell’espressione della tabella interna non causerà alcun sovraccarico non necessario recuperando e ignorando le colonne non necessarie .

In linea di massima SELECT * dovrebbe andare bene in una vista così come lo è il SELECT finale dalla vista in cui dovrebbe essere evitato, tuttavia in SQL Server questo può causare problemi poiché memorizza i metadati della colonna per le viste che non vengono automaticamente aggiornati quando il le tabelle sottostanti cambiano e l’uso di * può portare a risultati confusi e errati a meno che sp_refreshview non sp_refreshview eseguito per aggiornare questi metadati.

Esistono molti scenari in cui SELECT * è la soluzione ottimale. Esecuzione di query ad hoc in Management Studio solo per avere un’idea dei dati con cui si sta lavorando. Interrogare le tabelle in cui non si conoscono ancora i nomi delle colonne perché è la prima volta che si lavora con un nuovo schema. Costruire strumenti quick’n’dirty usa e getta per eseguire una migrazione o esportazione di dati una tantum.

Sono d’accordo che nello sviluppo “corretto”, dovresti evitarlo – ma ci sono molti scenari in cui lo sviluppo “corretto” non è necessariamente la soluzione ottimale per un problema aziendale. Le regole e le migliori pratiche sono grandi, purché tu sappia quando interromperle. 🙂

Lo userò in produzione quando lavoro con CTE. Ma in questo caso non è davvero select * , perché ho già specificato le colonne nel CTE. Non voglio proprio rispecificare nella selezione finale.

 with t as ( select a, b, c from foo ) select t.* from t; 

Nessuno a cui possa pensare, se parli di codice live.

Le persone che dicono che rende l’aggiunta di colonne più facile da sviluppare (in modo che vengano automaticamente restituite e possano essere utilizzate senza modificare la stored procedure) non hanno idea di scrivere codice / sql ottimale.

Lo uso sempre solo durante la scrittura di query ad hoc che non verranno riutilizzate (trovare la struttura di una tabella, ottenere alcuni dati quando non sono sicuro di quali siano i nomi delle colonne).

Penso che usare select * in una clausola exist sia appropriato:

 select some_field from some_table where exists (select * from related_table [join condition...]) 

Ad alcune persone piace usare select 1 in questo caso, ma non è elegante e non acquista alcun miglioramento delle prestazioni (l’ottimizzazione iniziale colpisce ancora).

Nel codice di produzione, sarei tendenzialmente d’accordo al 100% con te.

Tuttavia, penso che il * più che giustifichi la sua esistenza quando si eseguono query ad-hoc.

Hai ottenuto una serie di risposte alla tua domanda, ma sembra che tu stia liquidando tutto ciò che non ripete a pappagallo quello che vuoi sentire. Tuttavia, eccoci per il terzo (finora) tempo: a volte non ci sono strozzature. A volte le prestazioni sono molto meglio che bene. A volte le tabelle sono in stream e la modifica di ogni query SELECT rappresenta solo un ulteriore bit di incongruenza da gestire. A volte devi rispettare un programma imansible e questa è l’ultima cosa a cui devi pensare.

Se vivi in ​​tempo utile, sicuro, digita tutti i nomi delle colonne. Ma perché fermarsi qui? Riscrivi la tua app in un dbms senza schema. Diavolo, scrivi il tuo dbms in assemblea. Questo li avrebbe davvero mostrati.

E ricorda che se si seleziona select * e si ha un join, almeno un campo verrà inviato due volte (il campo join). Questo spreca risorse del database e risorse di rete senza motivo.

Come strumento lo uso per aggiornare rapidamente la mia memoria su cosa posso tornare da una query. Come una query di livello di produzione in sé .. nessun modo.

Quando crei un’applicazione che si occupa del database, come phpmyadmin, e ti trovi in ​​una pagina in cui visualizzare una tabella completa, in questo caso l’utilizzo di SELECT * può essere giustificato, suppongo.

Circa l’unica cosa che posso pensare sarebbe quando si sviluppa un’utilità o un’applicazione dello strumento SQL che viene scritta per essere eseguita su qualsiasi database. Anche qui, tuttavia, tenderei a interrogare le tabelle di sistema per ottenere la struttura della tabella e quindi creare una query necessaria da quella.

C’era un luogo recente in cui il mio team usava SELECT * e penso che fosse ok … abbiamo un database che esiste come facciata contro un altro database (chiamiamolo DB_Data), quindi è principalmente costituito da viste contro le tabelle nell’altro database. Quando generiamo le viste, in realtà generiamo gli elenchi di colonne, ma nel database DB_Data esiste un gruppo di viste che vengono generate automaticamente quando le righe vengono aggiunte a una tabella di ricerca generica (questo progetto era in vigore prima che arrivassi qui). Abbiamo scritto un trigger DDL in modo che quando una vista viene creata in DB_Data da questo processo, un’altra vista viene creata automaticamente nella facciata. Poiché la vista viene sempre generata per corrispondere esattamente alla vista in DB_Data e viene sempre aggiornata e mantenuta sincronizzata, abbiamo semplicemente usato SELECT * per semplicità.

Non sarei sorpreso se la maggior parte degli sviluppatori passasse la loro intera carriera senza avere un uso legittimo per SELECT * nel codice di produzione.

Ho usato select * per interrogare tabelle ottimizzate per la lettura (denormalizzata, dati flat). Molto vantaggioso in quanto lo scopo delle tabelle era semplicemente quello di supportare varie visualizzazioni nell’applicazione.

In quale altro modo gli sviluppatori di phpmyadmin assicurano che visualizzino tutti i campi delle tabelle DB?

È concepibile che si desideri progettare il DB e l’applicazione in modo da poter aggiungere una colonna a un tavolo senza dover riscrivere l’applicazione. Se la tua applicazione controlla almeno i nomi delle colonne, può tranquillamente utilizzare SELECT * e trattare le colonne aggiuntive con alcune azioni predefinite appropriate. Certo l’app potrebbe consultare i cataloghi di sistema (o cataloghi specifici per app) per le informazioni sulle colonne, ma in alcune circostanze SELECT * è zucchero sintattico per farlo.

Esistono tuttavia rischi evidenti e aggiungere la logica necessaria all’app per renderlo affidabile potrebbe semplicemente significare replicare i controlli delle query del DB in un supporto meno adatto. Non ho intenzione di speculare su come i costi e i benefici si compensino nella vita reale.

In pratica, mi atteno a SELECT * per 3 casi (alcuni citati in altre risposte:

  • Come una query ad-hoc, immessa in una GUI o riga di comando SQL.
  • Come il contenuto di un predicato EXISTS .
  • In un’applicazione che si occupa di tabelle generiche senza bisogno di sapere cosa significano (ad esempio un dumper o differiscono).

Sì, ma solo in situazioni in cui l’intenzione è di ottenere effettivamente tutte le colonne da una tabella, non perché si desidera che tutte le colonne attualmente presenti in una tabella.

Ad esempio, in un sistema su cui ho lavorato, avevamo le UDF (User Defined Fields) in cui l’utente poteva selezionare i campi che desiderava sul report, l’ordine e il filtro. Quando si creava un set di risultati, aveva più senso semplicemente “selezionare *” dalle tabelle temporanee che stavo costruendo invece di dover tenere traccia di quali colonne erano attive.

  1. Ho più volte bisogno di visualizzare i dati da una tabella i cui nomi di colonna erano sconosciuti. Così ho fatto SELECT * e ho ottenuto i nomi delle colonne in fase di esecuzione.

  2. Mi è stata consegnata un’app legacy in cui un tavolo aveva 200 colonne e una vista ne aveva 300. L’esposizione al rischio di SELECT * sarebbe stata peggiore di quella di elencare tutte le 300 colonne esplicitamente.

Dipende dal contesto del software di produzione.

Se si sta scrivendo un semplice livello di accesso ai dati per uno strumento di gestione delle tabelle in cui l’utente selezionerà le tabelle e visualizzerà i risultati in una griglia, sembrerebbe che * SELECT ** sia soddisfacente.

In altre parole, se si sceglie di gestire “selezione dei campi” con altri mezzi (come nei filtri automatici o specificati dall’utente dopo aver recuperato il set di risultati), allora sembra giusto.

Se d’altra parte stiamo parlando di una sorta di software aziendale con regole di business, uno schema definito, ecc … quindi sono d’accordo che * SELECT ** è una ctriggers idea.

EDIT: Oh e quando la tabella di origine è una procedura memorizzata per un trigger o una vista, “* SELECT **” dovrebbe andare bene perché si sta gestendo il set di risultati con altri mezzi (la definizione della vista o il set di risultati del processo memorizzato).

Select * nel codice di produzione è giustificabile in qualsiasi momento:

  • non è un collo di bottiglia per le prestazioni
  • il tempo di sviluppo è fondamentale

Perché dovrei volere il sovraccarico di tornare indietro e dovermi preoccupare di cambiare le stored procedure rilevanti, ogni volta che aggiungo un campo al tavolo?

Perché dovrei anche voler pensare se ho selezionato i campi giusti, quando la maggior parte delle volte voglio la maggior parte di loro comunque, e la stragrande maggioranza delle poche volte che non lo faccio, qualcos’altro è il collo di bottiglia?

Se ho un problema di prestazioni specifico, tornerò e risolverlo. Altrimenti nel mio ambiente, è solo l’ottimizzazione prematura (e costosa) di cui posso fare a meno.


Modifica … dopo la discussione, suppongo di aggiungere a questo:

… e dove le persone non hanno fatto altre cose indesiderabili come provare ad accedere alle colonne (i), che potrebbero comunque irrompere in altre situazioni 🙂

So che sono in ritardo per la festa ma farò il chip in che uso select * ogni volta che so che vorrò sempre tutte le colonne indipendentemente dai nomi delle colonne. Questo potrebbe essere un caso piuttosto marginale ma nel data warehousing, potrei voler mettere in scena un’intera tabella da un’app di terze parti. Il mio processo standard per questo è quello di rilasciare la tabella di staging ed eseguire

 select * into staging.aTable from remotedb.dbo.aTable 

Sì, se lo schema nella tabella remota cambia, le dipendenze downstream possono generare errori, ma ciò avverrà indipendentemente.

Se vuoi trovare tutte le colonne e vuoi ordinare, puoi fare quanto segue (almeno se usi MySQL):

SHOW COLUMNS FROM mytable FROM mydb; (1)

Puoi vedere tutte le informazioni rilevanti su tutti i tuoi campi. Puoi evitare problemi con i tipi e puoi sapere con certezza tutti i nomi delle colonne. Questo comando è molto veloce, perché basta chiedere la struttura del tavolo. Dai risultati selezionerai tutto il nome e costruirai una stringa come questa:

 "select " + fieldNames[0] + ", fieldNames[1]" + ", fieldNames[2] from mytable". (2) 

Se non si desidera eseguire due comandi MySQL separati perché un comando MySQL è costoso, è ansible includere (1) e (2) in una procedura memorizzata che avrà i risultati come parametro OUT, in questo modo si chiamerà semplicemente un stored procedure e ogni comando e generazione di dati avverranno sul server del database.