2012-01-05 44 views
47

So che le domande con questo titolo hanno avuto risposta prima, ma per favore continua a leggere. Ho letto attentamente tutte le altre domande/risposte su questo errore prima di postare.# 1071 - La chiave specificata era troppo lunga; la lunghezza massima della chiave è 1000 byte

sto ottenendo l'errore precedente per la seguente query:

CREATE TABLE IF NOT EXISTS `pds_core_menu_items` (
    `menu_id` varchar(32) NOT NULL, 
    `parent_menu_id` int(32) unsigned DEFAULT NULL, 
    `menu_name` varchar(255) DEFAULT NULL, 
    `menu_link` varchar(255) DEFAULT NULL, 
    `plugin` varchar(255) DEFAULT NULL, 
    `menu_type` int(1) DEFAULT NULL, 
    `extend` varchar(255) DEFAULT NULL, 
    `new_window` int(1) DEFAULT NULL, 
    `rank` int(100) DEFAULT NULL, 
    `hide` int(1) DEFAULT NULL, 
    `template_id` int(32) unsigned DEFAULT NULL, 
    `alias` varchar(255) DEFAULT NULL, 
    `layout` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`menu_id`), 
    KEY `index` (`parent_menu_id`,`menu_link`,`plugin`,`alias`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

Qualcuno ha idea del perché e come risolvere il problema? Il problema è: questa stessa query funziona perfettamente sul mio computer locale e ha funzionato anche sul mio precedente host. Btw.it è di un progetto maturo - phpdevshell - quindi immagino che questi ragazzi sappiano cosa stanno facendo, anche se non lo saprai mai.

Qualsiasi indizio apprezzabile.

Sto usando phpMyAdmin.

risposta

94

Come dice @Devart, la lunghezza totale dell'indice è troppo lunga.

La risposta breve è che non dovresti comunque indicizzare colonne VARCHAR così lunghe, perché l'indice sarà molto ingombrante e inefficiente.

La procedura consigliata è utilizzare gli indici di prefisso in modo da indicizzare solo una sottostringa sinistra dei dati. La maggior parte dei tuoi dati sarà comunque molto più breve di 255 caratteri.

È possibile dichiarare una lunghezza prefisso per colonna mentre si definisce l'indice. Ad esempio:

... 
KEY `index` (`parent_menu_id`,`menu_link`(50),`plugin`(50),`alias`(50)) 
... 

Ma qual è la lunghezza del prefisso migliore per una determinata colonna? Ecco un metodo per scoprire:

SELECT 
ROUND(SUM(LENGTH(`menu_link`)<10)*100/COUNT(*),2) AS pct_length_10, 
ROUND(SUM(LENGTH(`menu_link`)<20)*100/COUNT(*),2) AS pct_length_20, 
ROUND(SUM(LENGTH(`menu_link`)<50)*100/COUNT(*),2) AS pct_length_50, 
ROUND(SUM(LENGTH(`menu_link`)<100)*100/COUNT(*),2) AS pct_length_100 
FROM `pds_core_menu_items`; 

Vi dice la percentuale di righe che non hanno più di una data lunghezza della stringa nella colonna menu_link. Si potrebbe vedere output come questo:

+---------------+---------------+---------------+----------------+ 
| pct_length_10 | pct_length_20 | pct_length_50 | pct_length_100 | 
+---------------+---------------+---------------+----------------+ 
|   21.78 |   80.20 |  100.00 |   100.00 | 
+---------------+---------------+---------------+----------------+ 

Questo vi dice che l'80% delle corde sono meno di 20 caratteri, e tutte le corde sono meno di 50 caratteri. Quindi non c'è bisogno di indicizzare più di una lunghezza prefissata di 50, e certamente non c'è bisogno di indicizzare l'intera lunghezza di 255 caratteri.

PS: I tipi di dati INT(1) e INT(32) indicano un'altra incomprensione su MySQL. L'argomento numerico non ha alcun effetto relativo alla memoria o all'intervallo di valori consentito per la colonna.INT è sempre 4 byte e consente sempre valori da -2147483648 a 2147483647. L'argomento numerico riguarda i valori di riempimento durante la visualizzazione, che non ha alcun effetto a meno che non si utilizzi l'opzione ZEROFILL.

+6

Grazie mille per la spiegazione dettagliata. Oltre a risolvere un problema, ho anche imparato qualcosa di prezioso. – CodeVirtuoso

+1

Questa è una query chiara, grazie per la condivisione! – yekta

+0

Query davvero molto utile per trovare la lunghezza a cui impostare l'indice. Lo abbiamo usato alcune volte per determinare la lunghezza migliore per un indice. Grazie per aver condiviso! –

17

Questo errore indica che la lunghezza dell'indice index è maggiore di 1000 byte. MySQL e i motori di archiviazione potrebbero avere questa restrizione. Ho un errore simile su MySQL 5.5: "La chiave specificata era troppo lunga; max lunghezza della chiave è 3072 byte quando correva questo script:

CREATE TABLE IF NOT EXISTS test_table1 (
    column1 varchar(500) NOT NULL, 
    column2 varchar(500) NOT NULL, 
    column3 varchar(500) NOT NULL, 
    column4 varchar(500) NOT NULL, 
    column5 varchar(500) NOT NULL, 
    column6 varchar(500) NOT NULL, 
    KEY `index` (column1, column2, column3, column4, column5, column6) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

UTF8 è multi-byte, e la lunghezza della chiave è calcolato in questo modo - 500 * 3 * 6 = 9000 byte.

Ma nota, la query successiva funziona!

CREATE TABLE IF NOT EXISTS test_table1 (
    column1 varchar(500) NOT NULL, 
    column2 varchar(500) NOT NULL, 
    column3 varchar(500) NOT NULL, 
    column4 varchar(500) NOT NULL, 
    column5 varchar(500) NOT NULL, 
    column6 varchar(500) NOT NULL, 
    KEY `index` (column1, column2, column3, column4, column5, column6) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

... perché ho usato charset = latin1, in questo caso, la lunghezza della chiave è 500 * 6 = 3000 byte.

+4

Grazie per la risposta, questo funziona, ma al costo di rinunciare a utf8 charset. Questa restrizione può essere in qualche modo superata (ho accesso completo al server), è lì per una buona ragione? – CodeVirtuoso

2

Questo limite di dimensioni dell'indice sembra essere maggiore nelle versioni a 64 bit di MySQL.

Stavo raggiungendo questa limitazione cercando di scaricare il nostro database di sviluppo e caricarlo su un VMWare virt locale. Alla fine ho capito che il server di sviluppo remoto era a 64 bit e avevo creato un virt a 32 bit. Ho appena creato un virt a 64 bit e sono stato in grado di caricare il database localmente.

5

eseguire questa query prima di creare o modificare la tabella.

SET @@global.innodb_large_prefix = 1;

questo imposterà la lunghezza max chiave per 3072 byte

1

ho appena fatto bypass questo errore, semplicemente cambiando i valori della "lunghezza" del database originale al totale di circa "1000 "cambiando la sua struttura, e quindi esportando lo stesso, sul server. :)

Problemi correlati