Nie, to nie ma być wątek o tym, czy Railsy są szybkie, albo dlaczego są wolne
Ale z okazji niedzieli może ktoś zechce się podzielić swoją opinią.
Po przeczytaniu bardzo ciekawego dla mnie tekstu http://mysqldump.azundris.com/archives/72-Rubyisms.html (poleconego na http://blog.rubyonrails.com/2007/7/20/rails-and-mysql) zacząłem się przyglądać swojej prostej aplikacji i urodziły mi się dwa pytania.
Pierwsze dotyczy opisanego problemu [color=blue]SELECT *[/color]. Zauważyłem, że moja prostolinijnie napisana aplikacja oczywiście jest pełna takich zapytań, generowanych czy to poprzez normalne find czy poprzez dynamiczne findery. Co prawda nie mam zbyt wiele pól typu text, żeby tak bardzo marwić się o wydajność mojej aplikacji (wewnętrzna firmowa, dla kilku/nastu osób), ale oczywiście chciałbym się uczyć robić rzeczy porządnie.
Mamy więc sytuację, gdzie mając dwa modele: Project i Client powiązane relacją (wiadomo, Project belongs_to :client) stosuję te piękne railsowe skróty:
@project = Project.find(params[:id]) # w kontrolerze
...
@project.client.name # w widoku
Chodzi o ten ostatni wiersz. Powoduje on oczywiście wygenerowanie [color=blue]SELECT * FROM clients WHERE (clients.id = 8)[/color] czyli odczytanie wszystkich pól z rekordu client[8], choć przy wykonywaniu tej konkretnej akcji jest potrzebne tylko kilka pól (nick, name) z dość rozbudowanego modelu Client, zawierającego pola typu text. Dla akcji typu [color=red]/project/show/92[/color] nie jest to może problem, bo odczytujemy tylko jeden rekord w relacji. Ale przy wyświetlaniu listy projektów [color=red]/project/index[/color] w logu ląduje ciąg nieprzyjemnych:
Client Load (0.000298) SELECT * FROM clients WHERE (clients.`id` = 8)
Client Load (0.000268) SELECT * FROM clients WHERE (clients.`id` = 5)
Client Load (0.000224) SELECT * FROM clients WHERE (clients.`id` = 101)
Client Load (0.000214) SELECT * FROM clients WHERE (clients.`id` = 1)
Client Load (0.000219) SELECT * FROM clients WHERE (clients.`id` = 100)
Client Load (0.000245) SELECT * FROM clients WHERE (clients.`id` = 4)
Client Load (0.000233) SELECT * FROM clients WER (clients.`id` = 2)
Client Load (0.000213) SELECT * FROM clients WHERE (clients.`id` = 8)
Client Load (0.000203) SELECT * FROM clients WHERE (clients.`id` = 1)
Client Load (0.000213) SELECT * FROM clients WHERE (clients.`id` = 4)
To jest oczywiście log z aplikacji odpalonej w środowisku development, ale w production log twierdzi, że na zapytania SQL zostało zużyte 28-29% czasu obsługi requesta, więc całkiem sporo? Jeszcze gorzej jest dla wyświetlania listy zadań, gdzie modelami w relacji są: projekt i klient, a do wyświetlenia listy zadań jest potrzebne tylko kilka pól z tych modeli zależnych.
Oczywiście mogę do odpowiednich modeli dodać kolejną metodę, np. client_short, która wykona find z użyciem opcji :select, dzięki czemu:
# zamiast tego:
@project.client.name
# będzie to:
@project.client_short.name
No i teraz pytanie jest proste: czy jest jakieś bardziej eleganckie rozwiązanie?
Oczywiście nadal kocham Rails za to, że przy szybkim tworzeniu aplikacji mogę po prostu napisać @project.client.name i mieć z głowy, a dopiero w razie problemów z wydajnością mogę trudne miejsca optymalizować czymś mniej pięknym ale wydajniejszym. Ale może jest w Railsach coś równie pięknego, ale polepszającego wydajność? 
