2010-11-07 10 views
6

Supponiamo di avere una grande tabella con tre colonne: "nome_utente", "proprietà_utente", "valore_di_proprietà". Supponiamo anche che io abbia un sacco di utenti (diciamo 100.000) e molte proprietà (diciamo 10.000). Quindi il tavolo sarà enorme (1 miliardo di righe).Posso ottimizzare il mio database dividendo un grande tavolo in molti piccoli?

Quando estraggo le informazioni dalla tabella, ho sempre bisogno di informazioni su un particolare utente. Quindi, io uso, ad esempio where user_name='Albert Gates'. Quindi, ogni volta che il server mysql deve analizzare 1 miliardo di righe per trovare quelle che contengono "Albert Gates" come user_name.

Non sarebbe opportuno dividere il grande tavolo in molti piccoli corrispondenti a utenti fissi?

+0

quello che stai descrivendo si chiama partizionamento. Nei database si progetta una struttura a griglia intorno ai dati. Si imposta l'hardware per gestire questo tipo di problema. Credo che la parttioning (che è il gergo di SQL Server per quello di cui si sta parlando) è una funzionalità che non è in MySQL - o 7 anni fa quando sono passato a SQL Server - che so che lo supporta. –

+0

@John Nicholas: http://dev.mysql.com/doc/refman/5.1/en/partitioning.html –

+0

coool tyvm;) mysql ha partizionamento dopotutto –

risposta

5

No, non penso sia una buona idea. Un approccio migliore è add an index nella colonna user_name e forse un altro indice su (user_name, user_property) per cercare una singola proprietà. Quindi il database non ha bisogno di eseguire la scansione di tutte le righe: è sufficiente trovare la voce appropriata nell'indice che è memorizzata in un B-Tree, rendendo facile trovare un record in un tempo molto breve.

Se l'applicazione è ancora lenta anche dopo aver indicizzato correttamente, a volte può essere una buona idea quella di partition le tabelle più grandi.

Un'altra cosa che è possibile considerare è la normalizzazione del database in modo che il nome_utente sia memorizzato in una tabella separata e utilizzi al suo posto una chiave per campi interi. Ciò può ridurre i requisiti di archiviazione e può aumentare le prestazioni. Lo stesso può valere per user_property.

+0

l'altro vantaggio della normalizzazione di user_name e l'utilizzo dell'ID in altre tabelle è che, se è necessario modificarlo, non è necessario aggiornare potenzialmente migliaia di record e tutte le loro relazioni. –

3

si dovrebbe normalizzare il vostro disegno come segue:

drop table if exists users; 
create table users 
(
user_id int unsigned not null auto_increment primary key, 
username varbinary(32) unique not null 
) 
engine=innodb; 

drop table if exists properties; 
create table properties 
(
property_id smallint unsigned not null auto_increment primary key, 
name varchar(255) unique not null 
) 
engine=innodb; 

drop table if exists user_property_values; 
create table user_property_values 
(
user_id int unsigned not null, 
property_id smallint unsigned not null, 
value varchar(255) not null, 
primary key (user_id, property_id), 
key (property_id) 
) 
engine=innodb; 

insert into users (username) values ('f00'),('bar'),('alpha'),('beta'); 

insert into properties (name) values ('age'),('gender'); 

insert into user_property_values values 
(1,1,'30'),(1,2,'Male'), 
(2,1,'24'),(2,2,'Female'), 
(3,1,'18'), 
(4,1,'26'),(4,2,'Male'); 

Dal punto di vista delle prestazioni l'indice InnoDB cluster fa miracoli in questo esempio simile (gelare):

select count(*) from product 
count(*) 
======== 
1,000,000 (1M) 

select count(*) from category 
count(*) 
======== 
250,000 (500K) 

select count(*) from product_category 
count(*) 
======== 
125,431,192 (125M) 

select 
c.*, 
p.* 
from 
product_category pc 
inner join category c on pc.cat_id = c.cat_id 
inner join product p on pc.prod_id = p.prod_id 
where 
pc.cat_id = 1001; 
0:00:00.030: Query OK (0.03 secs) 
+0

per favore commenta se tu non voti, altrimenti stai solo dimostrando la tua ignoranza. –

+0

Non credo di aver normalizzato nulla. Cosa è stato normlizzato? Che ordine di normalizzazione è? Quale ripetizione dei dati è stata eliminata? Inoltre (e questo è pignolo, mi dispiace) dove hai intenzione di memorizzare il valore della proprietà? Vuoi davvero che le proprietà abbiano molte relazioni? Attualmente ogni proprietà può essere condivisa tra più utenti e sarà molto difficile avere proprietà richieste. –

+0

scusami l'ho cancellato mentre riflettevo. –

1

Perché voi bisogno di avere questa struttura della tabella Il mio problema fondamentale è che dovrai trasmettere i dati in valore di proprietà ogni volta che desideri utilizzarli. Questo a mio avviso non va bene, anche memorizzando i numeri in quanto il testo è pazzesco dato che è comunque tutto binario. Ad esempio, come hai intenzione di avere campi obbligatori? O campi che devono avere vincoli basati su altri campi? Es. Data di inizio e fine?

Perché non avere semplicemente le proprietà come campi piuttosto che alcuni rapporti molti a molti?

hanno 1 tavolo piatto. Quando le regole aziendali iniziano a mostrare che le proprietà devono essere raggruppate, puoi considerare di spostarle in altre tabelle e avere diverse relazioni 1: 0-1 con la tabella degli utenti. Ma questa non è normalizzazione e peggiorerà leggermente le prestazioni a causa dell'aggiunta aggiuntiva (tuttavia la natura autodocumentante dei nomi delle tabelle sarà di grande aiuto per gli sviluppatori)

Un modo in cui vedo regolarmente le prestazioni del databqase ottenere completamente castrato è di avere un generico

Id, tipo proprietà, nome proprietà, tabella valori proprietà.

Questo è veramente pigro ma eccezionalmente flessibile, ma uccide totalmente le prestazioni. In effetti, in un nuovo lavoro in cui le prestazioni sono cattive, in realtà chiedo se hanno una tabella con questa struttura: invariabilmente diventa il punto centrale del database ed è lenta.L'intero punto della progettazione di database relazionali è che le relazioni sono determinate in anticipo. Questa è semplicemente una tecnica che mira ad accelerare lo sviluppo a un costo enorme per la velocità dell'applicazione. Implica anche un enorme affidamento sulla logica di business nel livello applicativo, che non è affatto difensivo. Alla fine si scopre che si desidera utilizzare le proprietà in una relazione chiave che porta a tutti i tipi di casting sul join che peggiora ulteriormente le prestazioni.

Se i dati hanno una relazione 1: 1 con un'entità, dovrebbe essere un campo sulla stessa tabella. Se il tuo tavolo raggiunge più di 30 campi, prendi in considerazione di spostarli in un'altra tabella ma non chiamarla normalizzazione perché non è. È una tecnica che aiuta gli sviluppatori a raggruppare i campi insieme al costo delle prestazioni nel tentativo di aiutare la comprensione.

Non so se mysql ha un equivalente ma sqlserver 2008 ha colonne sparse - i valori nulli non occupano spazio. SParse column datatypes

Non sto dicendo che un approccio EAV è sempre sbagliato, ma credo che utilizza un database relazionale per questo approccio non è probabilmente la scelta migliore.

2

L'indicizzazione corretta del database sarà il metodo numero 1 per migliorare le prestazioni. Una volta ho avuto una richiesta di prendere una mezz'ora (su un set di dati di grandi dimensioni, ma non per questo meno). Poi veniamo a scoprire che i tavoli non avevano indice. Una volta indicizzata, la query ha richiesto meno di 10 secondi.

Problemi correlati