# Εξοντώνοντας τα n+1 προβλήματα με ομαδοποίηση

Ας πούμε ότι έχεις τα παρακάτω δεδομένα σε ένα αρχείο .csv και έναν πίνακα users με στήλες id και first\_name στη βάση σου.

| Database ID | First name |
| --- | --- |
| 1 | Nick |
| 2 | Nick |
| 3 | Alex |
| 4 | Alex |
| 5 | Panos |
| 6 | Panos |

Φαντάσου ότι θέλεις να ενημερώσεις προγραμματιστικά τη στήλη first\_name με τα αντίστοιχα δεδομένα από το csv.

Το σύνολο δεδομένων είναι αρκετά μικρό ώστε να μπορούμε να τρέξουμε ένα update query για κάθε γραμμή. Αν όμως οι εγγραφές ήταν χιλιάδες, αυτό πιθανότατα θα έπαιρνε πολύ περισσότερο χρόνο ή θα αποτύγχανε εντελώς.

Αυτό που χρειάζεται είναι να διαβάσουμε τα δεδομένα από το αρχείο και μετά να τα ομαδοποιήσουμε/μετατρέψουμε σε dictionaries, hashes, associative arrays ή ό,τι άλλο προσφέρει η γλώσσα προγραμματισμού που προτιμάς. Εδώ θα πάμε με json.

```json
{
"Nick": [1, 2]
"Alex": [3, 4]
"Panos": [5, 6]
}
```

Τώρα, αντί να ενημερώνουμε κάθε εγγραφή ξεχωριστά, μπορούμε να τις ενημερώσουμε μαζικά ανά ομάδα 🎉

```sql
UPDATE users SET first_name = Nick WHERE id IN (1, 2);
```

```sql
UPDATE users SET first_name = Alex WHERE id IN (3, 4);
```

```sql
UPDATE users SET first_name = Panos WHERE id IN (5, 6);
```

Αν χρησιμοποιείς ένα ORM όπως το ActiveRecord του Rails ή το Eloquent του Laravel, πιθανότατα θα φόρτωνες πρώτα τις εγγραφές και μετά θα τις ενημέρωνες αναλόγως.

Στο Rails θα έκανες κάτι τέτοιο:

```ruby
data = {
    "Nick" => [1, 2]
    "Alex" => [3, 4]
    "Panos" => [5, 6]
}

data.each do |name, record_ids|
    User.where(id: record_ids).update_all(first_name: name)
end
```

Παρ' όλα αυτά, υπάρχουν τρόποι να στύψεις λίγη παραπάνω απόδοση. Το να διαβάζεις το αρχείο σε batches και να χρησιμοποιείς το `find_in_batches` του Rails θα βοηθήσει πιθανότατα να εξοικονομήσεις μνήμη, ή μπορείς ακόμα και να παρακάμψεις το ORM και να κατέβεις σε raw SQL.