Простым способом, который я использовал, является слияние после того, как 2 groupby выполнили простое деление.
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
'office_id': list(range(1, 7)) * 2,
'sales': [np.random.randint(100000, 999999) for _ in range(12)]})
state_office = df.groupby(['state', 'office_id'])['sales'].sum().reset_index()
state = df.groupby(['state'])['sales'].sum().reset_index()
state_office = state_office.merge(state, left_on='state', right_on ='state', how = 'left')
state_office['sales_ratio'] = 100*(state_office['sales_x']/state_office['sales_y'])
state office_id sales_x sales_y sales_ratio
0 AZ 2 222579 1310725 16.981365
1 AZ 4 252315 1310725 19.250033
2 AZ 6 835831 1310725 63.768601
3 CA 1 405711 2098663 19.331879
4 CA 3 710581 2098663 33.858747
5 CA 5 982371 2098663 46.809373
6 CO 1 404137 1096653 36.851857
7 CO 3 217952 1096653 19.874290
8 CO 5 474564 1096653 43.273852
9 WA 2 535829 1543854 34.707233
10 WA 4 548242 1543854 35.511259
11 WA 6 459783 1543854 29.781508
767 байт является установленным префиксным ограничением для таблиц InnoDB в MySQL версии 5.6 (и предыдущих версиях). Это 1000 байтов для таблиц MyISAM. В MySQL версии 5.7 и выше этот предел был увеличен до 3072 байт.
Вы также должны знать, что если вы установите индекс в большом поле char или varchar, кодируемом utf8mb4, вам нужно разделить максимальная длина префикса индекса 767 байтов (или 3072 байта) на 4, что приводит к 191. Это связано с тем, что максимальная длина символа utf8mb4 составляет четыре байта. Для символа utf8 это будет три байта, в результате чего максимальная длина префикса индекса будет равна 254.
Один из вариантов - просто установить нижний предел для полей VARCHAR.
Еще один вариант ( в соответствии с ответом на эту проблему ) заключается в том, чтобы получить подмножество столбца, а не всю сумму, то есть:
ALTER TABLE `mytable` ADD UNIQUE ( column1(15), column2(200) );
Тройка, поскольку вам нужно получить ключ от применим, но мне интересно, стоит ли рассматривать вашу модель данных относительно этого объекта, чтобы увидеть, есть ли улучшения, которые позволят вам реализовать намеченные бизнес-правила, не нарушая ограничений MySQL.
Если вы создаете что-то вроде:
CREATE TABLE IF NOT EXISTS your_table (
id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar(256) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY name (name)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;
, это должно быть что-то вроде
CREATE TABLE IF NOT EXISTS your_table (
id int(7) UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar(256) COLLATE utf8mb4_bin NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ROW_FORMAT=FIXED;
, но вам нужно проверить уникальность этого столбца из кода или добавить новый столбец как MD5 или SHA1 столбца varchar
Для меня проблема с «# 1071 - указанный ключ была слишком длинной, длина ключа - 767 байт» была решена после изменения комбинации primarykey / uniquekey, ограничив размер столбца на 200.
ALTER TABLE `mytable` ADD UNIQUE (
`column1` (200) ,
`column2` (200)
);
Я сделал некоторые поиски по этой теме, наконец, получил некоторые пользовательские изменения
Для Workbench MySQL 6.3.7 Версия доступна графическая межфазная
Для версий ниже 6.3.7 прямые параметры недоступны, поэтому вам нужно перейти с командной строкой
set global innodb_default_row_format = DYNAMIC;
, я вижу это сообщение: ERROR 1193 (HY000): Неизвестная системная переменная 'innodb_default_row_format'
– Adrian Cid Almaguer
24 January 2017 в 15:58
Когда вы достигли предела. Установите следующее:
utf8
VARCHAR(255)
utf8mb4
VARCHAR(191)
utf8mb4
(который является наиболее часто используемым кодированием для новых баз данных, поскольку он принимает emojis / etc).
– Claudio Holanda
8 September 2016 в 00:48
ENGINE=InnoDB DEFAULT CHARSET=utf8
в конце оператора CREATE TABLE
, я смог получить первичный ключ VARCHAR(255)
. Благодарю.
– xonya
10 June 2018 в 14:07
Решение для Laravel Framework
Согласно Laravel 5.4. * документация ; Вы должны установить длину строки по умолчанию внутри метода
boot
в
app / Providers / AppServiceProvider. php
следующим образом:
use Illuminate\Support\Facades\Schema; public function boot() { Schema::defaultStringLength(191); }
Объяснение этого исправления, данное Laravel 5.4. * documentation ;
Laravel использует набор символов utf8mb4 по умолчанию, который включает поддержку для хранения «emojis» в базе данных. Если вы используете версию MySQL старше версии 5.7.7 или MariaDB старше версии 10.2.2, вам может потребоваться вручную настроить длину строки по умолчанию, сгенерированную миграциями, чтобы MySQL создавал для них индексы. Вы можете настроить это, вызывая метод Schema :: defaultStringLength в вашем AppServiceProvider
. Кроме того, вы можете включить параметр innodb_large_prefix для вашей базы данных. Обратитесь к документации вашей базы данных, чтобы узнать, как правильно включить эту опцию.
Какую кодировку символов вы используете? Некоторые наборы символов (например, UTF-16 и т. Д.) Используют более одного байта на символ.
20 * 4 + 1
байт, а столбец 500 символов - 500 * 4 + 2
байт
– Thanatos
29 November 2009 в 04:46
VARCHAR(256)
с индексом UNIQUE
изменение сортировки не повлияло на меня, как это было для @Andresch. Однако уменьшение длины от 256 до 255 действительно позволило решить эту проблему. Я не понимаю, почему, поскольку 767 / max 4 байта на символ даст максимум 191?
– Arjan
5 November 2012 в 16:45
255*3 = 765; 256*3 = 768
. Кажется, ваш сервер был asssuming 3 байта на символ, @Arjan
– Amber
5 November 2012 в 18:11
Я нашел этот запрос полезным при определении того, какие столбцы имели индекс, нарушающий максимальную длину:
SELECT
c.TABLE_NAME As TableName,
c.COLUMN_NAME AS ColumnName,
c.DATA_TYPE AS DataType,
c.CHARACTER_MAXIMUM_LENGTH AS ColumnLength,
s.INDEX_NAME AS IndexName
FROM information_schema.COLUMNS AS c
INNER JOIN information_schema.statistics AS s
ON s.table_name = c.TABLE_NAME
AND s.COLUMN_NAME = c.COLUMN_NAME
WHERE c.TABLE_SCHEMA = DATABASE()
AND c.CHARACTER_MAXIMUM_LENGTH > 191
AND c.DATA_TYPE IN ('char', 'varchar', 'text')
Если вы недавно изменили innodb_log_file_size
, попытайтесь восстановить предыдущее значение, которое сработало.
Specified key was too long; max key length is 767 bytes
Вы получили это сообщение, потому что 1 байт равен 1 символу, только если вы используете набор символов latin-1
. Если вы используете utf8
, каждый символ будет считаться 3 байтами при определении столбца ключа. Если вы используете utf8mb4
, каждый символ будет считаться 4 байтами при определении столбца ключа. Таким образом, вам нужно умножить предел символов вашего ключевого поля на, 1, 3 или 4 (в моем примере), чтобы определить количество байт, которые ключевое поле пытается разрешить. Если вы используете uft8mb4, вы можете определить только 191 символ для собственного поля InnoDB, primary key. Просто не нарушайте 767 байт.
Я думаю, что varchar (20) требует только 21 байт, а varchar (500) требует всего 501 байт. Таким образом, суммарные байты 522, меньше 767. Итак, почему я получил сообщение об ошибке?
blockquote>UTF8 требует 3 байта на символ для хранения строки, поэтому в вашем случае 20 + 500 символов = 20 * 3 + 500 * 3 = 1560 байт, что более чем допустимо 767 байт.
Предел для UTF8 составляет 767/3 = 255 символов, для UTF8mb4, который использует 4 байта на символ, это 767 / 4 = 191 символ.
Для этой проблемы существует два решения, если вам нужно использовать более длинный столбец, чем предел:
- Используйте «более дешевую» кодировку ( один, который требует меньше байтов на символ). В моем случае мне нужно было добавить уникальный индекс в столбец, содержащий строку SEO-статьи, поскольку я использую только
[A-z0-9\-]
символов для SEO, я использовалlatin1_general_ci
, который использует только один байт на символ и поэтому столбец может иметь длину 767 байт.- Создайте хэш из своего столбца и используйте уникальный индекс только для этого. Другим вариантом для меня было создание еще одного столбца, в котором будет храниться хэш SEO, в этом столбце будет
UNIQUE
ключ, чтобы гарантировать, что значения SEO уникальны , Я бы также добавил индексKEY
к исходной колонке SEO, чтобы ускорить поиск.
В моем случае у меня была эта проблема, когда я создавал резервную копию базы данных с использованием выходных / входных символов перенаправления linux. Поэтому я изменяю синтаксис, как описано ниже. PS: использование терминала linux или mac.
Резервное копирование (без> перенаправления)
# mysqldump -u root -p databasename -r bkp.sql
Восстановление (без & lt; редирект)
# mysql -u root -p --default-character-set=utf8 databasename
mysql> SET names 'utf8'
mysql> SOURCE bkp.sql
Ошибка «Указанный ключ был слишком длинным, максимальная длина ключа - 767 байт» исчезла.
Вот мой оригинальный ответ:
Я просто отбрасываю базу данных и воссоздаю вот так, и ошибка исчезла:
drop database if exists rhodes; create database rhodes default CHARACTER set utf8 default COLLATE utf8_general_ci;
Однако это не работает для всех случаев.
На самом деле проблема использования индексов в столбцах VARCHAR с набором символов
utf8
(илиutf8mb4
) с столбцами VARCHAR с более чем определенной длиной символов. В случаеutf8mb4
эта определенная длина равна 191.Для получения дополнительной информации о том, как использовать длинные индексы в базе данных MySQL, см. Раздел «Лонг-индекс» в этой статье: http: // hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database-character-set-to-utf8mb4
Если вы запустите Laravel (теперь для laravel по умолчанию используется 4-байтовый Unicode), вы можете решить это, изменив следующие строки в config / database.php из
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
 на
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
utf8
с utf8mb4
.
– Player1
16 July 2018 в 19:42
В соответствии с приведенным ниже столбцом эти 2 столбца с переменной строкой используют utf8_general_ci
сопоставление (подразумевается кодировка utf8
).
В MySQL, utf8
charset использует максимум 3 байта для каждого символа. Таким образом, ему нужно будет выделить 500 * 3 = 1500 байт, что намного больше, чем позволяет 767 байт MySQL. Вот почему вы получаете эту ошибку 1071.
Другими словами, вам нужно вычислить количество символов на основе байтового представления charset, так как не каждая кодировка представляет собой однобайтовое представление (как вы предполагали). I.E. utf8
в MySQL использует не более 3 байтов на символ, 767 / 3≈255 символов, а для utf8mb4
- не более 4-байтового представления, 767 / 4≈191 символов.
Также известно, что MySQL
column1 varchar(20) utf8_general_ci
column2 varchar(500) utf8_general_ci
вы можете добавить столбец md5 длинных столбцов
запустите этот запрос перед вашим запросом:
SET @@global.innodb_large_prefix = 1;
это увеличит предел до 3072 bytes
.
Я исправил эту проблему с помощью:
varchar(200)
, замененного на
varchar(191)
, все varchar, которые имеют более 200, заменяют их 191 или устанавливают их текст.
Ответ на вопрос о том, почему вы получили сообщение об ошибке, уже ответили многие пользователи здесь. Мой ответ о том, как исправить и использовать его как есть.
Обратитесь к этой ссылке .
use my_database_name;
База данных изменена
set global innodb_large_prefix=on;
Запрос ОК, 0 строк затронуты (0.00 сек)
set global innodb_file_format=Barracuda;
Query OK, 0 строк затронуты (0,02 сек)
- Перейдите в свою базу данных на phpMyAdmin или что-то вроде этого для удобства управления. > Выберите базу данных> Просмотреть структуру таблицы> Перейдите на вкладку «Операции». > Измените ROW_FORMAT на DYNAMIC и сохраните изменения.
- Перейдите на вкладку структуры таблицы> Нажмите кнопку «Уникальная».
- Готово. Теперь у него не должно быть ошибок.
Проблема этого исправления заключается в том, что вы экспортируете db на другой сервер (например, с локального хоста на реальный хост), и вы не можете использовать командную строку MySQL на этом сервере , Вы не можете заставить его работать.
Для laravel 5.6
Шаги к следующему
, что все, Наслаждайтесь.
Просто изменив utf8mb4
на utf8
при создании таблиц, решила мою проблему. Например: CREATE TABLE ... DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
- CREATE TABLE ... DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
.
Мы столкнулись с этой проблемой при попытке добавить индекс UNIQUE в поле VARCHAR (255), используя utf8mb4. Хотя проблема уже здесь хорошо описана, я хотел бы добавить несколько практических советов, как мы это выяснили и решили.
При использовании utf8mb4 символы считаются 4 байтами, тогда как под utf8 они могут как 3 байта. Базы данных InnoDB имеют ограничение на то, что индексы могут содержать только 767 байт. Поэтому при использовании utf8 вы можете сохранить 255 символов (767/3 = 255), но используя utf8mb4, вы можете хранить только 191 символ (767/4 = 191).
Вы абсолютно можете добавить регулярные индексы для полей VARCHAR(255)
с использованием utf8mb4, но случается, что размер индекса усекается с 191 символом автоматически - например unique_key
здесь:
Это прекрасно, потому что регулярные индексы просто используются для быстрого поиска MySQL через ваши данные. Все поле не нужно индексировать.
Итак, почему MySQL автоматически обрезает индекс для регулярных индексов, но бросает явную ошибку при попытке сделать это для уникальных индексов? Ну, для того, чтобы MySQL смог выяснить, существует ли уже существующее или обновляемое значение, оно должно фактически индексировать все значение, а не только его часть.
В конце дня, если вы хотите иметь уникальный индекс в поле, все содержимое поля должно вписываться в индекс. Для utf8mb4 это означает сокращение длины полей VARCHAR до 191 символа или меньше. Если вам не нужна utf8mb4 для этой таблицы или поля, вы можете вернуть ее обратно в utf8 и сохранить свои длины длины.
MySQL принимает наихудший случай для числа байтов на символ в строке. Для кодировки MySQL 'utf8' это 3 байта на символ, так как эта кодировка не допускает символов за пределами U+FFFF
. Для кодировки MySQL «utf8mb4» это 4 байта на символ, так как это то, что MySQL называет фактическим UTF-8.
. Предположим, вы используете «utf8», ваш первый столбец займет 60 байт индекс, а второй второй - 1500.
измените настройку. Вы можете использовать utf8_general_ci, который поддерживает почти все
Если у кого-то возникают проблемы с INNODB / Utf-8, пытающимися поместить индекс UNIQUE
в поле VARCHAR(256)
, переключите его на VARCHAR(255)
. Кажется, 255 является ограничением.
3*255 = 765 < 767
.
– Stefan Endrullis
23 July 2014 в 09:25
utf8
, который, к сожалению, сломан. Он может кодировать символы только в базовой многоязычной плоскости. Вы получите проблемы с персонажами, которые выходят за рамки этого. Например, те персонажи из Эможи, которые они добавляли, выходят за его пределы, я думаю. Поэтому вместо перехода на VARCHAR(255)
, переключитесь на VARCHAR(191)
и i>, переключите кодировку на utf8mb4
(на самом деле это просто utf8, но MySql хотел удержать. Compat).
– Stijn de Witt
5 December 2016 в 11:28
Измените CHARSET поля индекса жалобы на «latin1», то есть ALTER TABLE tbl CHANGE myfield myfield varchar (600) CHARACTER SET latin1 DEFAULT NULL; latin1 принимает один байт за один символ вместо четырех
Убедитесь, что sql_mode
подобен
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
, если он есть, измените на
sql_mode=NO_ENGINE_SUBSTITUTION
ИЛИ
перезапустите сервер, изменив свой файл my.cnf (установка следующий)
innodb_large_prefix=on
utf8mb4
(который остальная часть мира вызывает utf8), требуется (не более) 4 байта на символ , вы можете индексировать только доVARCHAR(191)
. Набор символов Mysqlutf8
(который весь мир вызывает поломку) требует не более 3 байтов на символ, поэтому, если вы используете это (вы не должны ), вы можете индексировать доVARCHAR(255)
– Stijn de Witt 5 December 2016 в 11:17