2015-06-08 8 views
0

У меня есть 5 текстовых полей, которые я хочу импортировать в базу данных MySQL/MariaDB. Но есть две проблемы:MySQL: использование естественного первичного индекса или добавление суррогата при указании таблиц

(1) Файлы довольно большие: 0,5 ГБ до 10 ГБ
(2) Все соответствующие клавиши имеют 40 символов

Point (1) я должен принять, как это и я не могу его изменить. Пункт 2 - мое беспокойство. В Интернете есть много предложений. Например, чтобы использовать перечисление для varchar или использовать числовые суррогаты. Нет необходимости добавлять суррогатный ключ к таблице. Но тот же самый суррогатный ключ должен быть добавлен к другим таблицам. И это тот момент, когда я застрял.

Здесь конкретная информация о файлах/таблицах:

  • таблица счета имеет 3 столбцов и 20 Mio строк:

    • invoice_id (первичный ключ) с различными значениями = число строки
    • praxis_id с 4 000 отличными значениями
    • patient_id с 4 Mio отдельные значения все столбцы CHAR (40) и имеют фиксированную длину 40.
  • таблице диагностики имеет 3 столбцов и 25 строк Mio:

    • invoice_id CHAR (40) 1.4 Мио отличается идентификатор
    • diagnose_type
    • diagnose_code
  • таблица пациент имеет 5 колонок с 5 рядами Mio:

    • patient_id CHAR (40) не уникально (4 Mio отличается pat_id)
    • praxis_id CHAR (40)
    • год рождения, пол и т.д.

Например, я хочу присоединиться к счету с диагнозом и пациентом. Имеет смысл индексировать ключи. Одним из способов было бы определить invoice.invoice_id как первичный ключ, а для всех остальных ключей в счет-фактуре таблицы я бы добавил индекс. То же самое с таблицей диагностики (invoice_id с INDEX) и пациентом (patient_id как первичный ключ).
Проблема заключается в том, что потребовалось много времени, чтобы определить invoice.invoice_id в качестве первичного ключа с помощью:

ALTER TABLE invoice_id ADD PRIMARY KEY(invoice_id); 

Через час я убил процесс. Я думаю, что одна из проблем производительности возникает из вида типа данных invoice_id в таблице счетов. Одной из идей может быть добавление автоинкрементного суррогатного ключа invoice_id_surr при загрузке текстового файла. Но, тем не менее, проблема остается, если я хочу присоединиться к диагностике таблицы, так как мне нужно присоединиться к invoice_id диагностики таблицы, которая не имеет суррогатного ключа invoice_id_surr в качестве внешнего ключа. Я мог бы добавить индекс для диагностики.invoice_id, но затем я теряю преимущество наличия суррогатного ключа в счете-фактуре.

Мне будет интересна стратегия, как справиться с этой проблемой: несколько уже существующих таблиц, которые могут быть объединены вместе, но ключи CHAR (40) и не имеют индекса.

Спасибо за помощь.


UPDATE 1: спецификация Таблица
- клавиши имеют 40 символов [0-9] [AZ]
- Это таблицы, которые не будут меняться больше (не вкладышами)

-- invoice_id is primary key (unique) 
-- patient_id and praxis id for foreign key and not unique in this table 
CREATE TABLE invoice (
    invoice_id    CHAR(40) DEFAULT NULL 
, praxis_id    CHAR(40) DEFAULT NULL 
, patient_id    CHAR(40) DEFAULT NULL 
, PRIMARY KEY (invoice_id2) 
) ENGINE = InnoDB 
; 

LOAD DATA LOCAL INFILE 'C:/data/invoice.txt' 
INTO TABLE invoice 
FIELDS TERMINATED BY '\t' 
LINES TERMINATED BY '\r\n' 
IGNORE 1 LINES 
; 

-- invoice_id is not unique in this table 
CREATE TABLE diagnose (
    invoice_id    CHAR(40) DEFAULT NULL 
, diagnose_katalog  VARCHAR(20) DEFAULT NULL 
, diagnose_code   VARCHAR(20) DEFAULT NULL 
) ENGINE = InnoDB 
; 
-- patient_id is not unique in this table since since patient may change praxis 
CREATE TABLE patient (
    patient_id    CHAR(40) DEFAULT NULL 
, praxis_id    CHAR(40) DEFAULT NULL 
, sex     CHAR(1)  DEFAULT NULL 
, birth_year    SMALLINT UNSIGNED DEFAULT NULL 
, zip_code    VARCHAR(20) DEFAULT NULL 
) ENGINE = InnoDB 
; 

ответ

1

Вам следует избегать использования естественных ключей в качестве первичных ключей в вашей базе данных по целому ряду причин, которые можно найти довольно легко при помощи Google.

Кроме того, что это означает, «даны таблицы»? Вы не должны настаивать на взаимном соответствии между текстовыми файлами и таблицами базы данных. Вместо этого вы должны проектировать свои таблицы таким образом, чтобы большинство соответствовало вашим потребностям. Стремитесь к нормализации.

Например, вы говорите, что patient_id в patient «таблица» (вы имеете в виду файл, справа?) Не уникальна. Очевидно, что вам нужна таблица, где пациенты уникальны; поэтому создайте таблицу с четкими patient_id и их атрибутами. patient_id должен быть уникальным ключом в этой таблице, но сгенерировать числовой суррогат (например, поле auto_increment), чтобы служить в качестве первичного ключа в этой таблице. После этого, например, создайте таблицу praxis с praxis_id как уникальный ключ и числовой суррогат для первичного ключа. Затем вы можете соединить patient и praxis с третьей таблицей, в зависимости от отношений «многие ко многим». Таким образом, вы нормализуете свою базу данных: пациент со своими атрибутами всегда является одной строкой в ​​одной таблице patient; в то время как теперь у вас один и тот же пациент вводил несколько раз в ваш текущий файл/таблицу patient, что рано или поздно вызовет у вас проблемы.

+0

@zgguv Спасибо за ответ. Я не прояснился. С «заданными» или «существующими» таблицами я имею в виду, что файл таблиц был экспортирован из внешней базы данных в виде текстовых файлов, и я не могу их изменить. Я не знаю, почему они использовали строки с 40 символами без смысла в качестве ключа вместо числового. Возможно, я ошибался, чтобы назвать этот ключ естественным (я назвал его так, потому что он был доставлен). Таблица ** пациент ** не имеет уникального _patient_id_, поскольку он имеет историзированную информацию о пациенте. Чтобы сделать это простым, забудьте ** ** таблицу пациента и посмотрите только на ** счет-фактуру ** и ** диагноз ** (отношение 1: n). (продолжение) – giordano

+0

@zgguv (продолжение) Нет необходимости добавлять числовой суррогатный ключ _invoice_ind2_ в ** счет **. Но этот суррогатный ключ также должен быть добавлен к ** диалогу ** как иностранному ключу, чтобы иметь возможность присоединиться к ** счету **. _invoice_id2_ = ** диагностировать **. _invoice_id2_. Поэтому я должен сначала добавить столбец ** диагноз **. _invoice_id2_ и 'update diagnose, invoice SET diagnose.invoice_id2 = invoice.invoice_id2 WHERE diagnose.invoice_id = invoice.invoice_id'. Я могу это сделать, но я должен добавить индекс для ** диагностики **. _invoice_id_ и ** диагностировать **. _invoice_id_. Итак, почему бы не использовать напрямую индексированный invoice_id для соединений? – giordano

+0

Это проблема барона Мюнхгаузена: выйти из моря он натягивает собственные волосы. Чтобы избежать строки в качестве ключа для объединений, я должен выполнять объединения с этими строками. – giordano

0

Я отвечаю на свой вопрос. Причиной этого сообщения было то, что я отправил запросы, например, определяя первичный ключ с ALTER TABLE ..., и процесс не прекращался через несколько часов. Как сказал @zgguv, продолжительность кажется не правдоподобной. Я остановил запросы и перезапустил (иногда после третьего раза), и процесс завершился через несколько минут (около 10 минут). Я не знаю, почему иногда запросы зависают. Это до сих пор не дошло до меня, но таблицы, которые я использовал, были намного меньше. Полученный урок:

  • Длинные строковые ключи следует заменить цифровыми клавишами, чтобы ускорить выбор.

  • Замена строчных ключей таблиц размером 10 ГБ (текстовая таблица), соответственно, 20 номеров строк Mio возможны (вам нужно только натягивать собственные волосы). Соединение между индексированными строковыми клавишами заняло около 10 минут.

  • Если длительность запроса занимает более 30 футов (отвес), остановите его и повторите попытку. Было бы неплохо узнать, почему это произошло (InnoDB, MyISAM, HeidiSQL, ...), но это еще одна проблема.

@zgguv Спасибо за поддержку и терпение.

1

У вас действительно есть CHAR(40), а не VARCHAR(40)? Значения всегда 40 символов? Является ли таблица CHARACTER SET utf8?

CHAR(40) utf8 принимает 120 байт всегда. Если вы сохраняете «Z» в таком поле, оно по-прежнему занимает 120 байт, а не только 1. Даже если вы импортируете 40 символов, объявив, что VARCHAR обрезает завершающие пробелы по мере их загрузки.

как минимум, я бы

ALTER TABLE foo 
    MODIFY col1 VARCHAR(40) ..., -- the "..." is other options for the col 
    MODIFY col2 VARCHAR(40) ..., 
    ...; 

Это, вероятно, поможет "точки (1)" много. И сделать все быстрее. (Предостережение: это займет много времени, чтобы закончить это ALTER.)

«Природные» ОСНОВНЫЕ КЛЮЧИ не являются злыми. Но используйте их там, где это необходимо. В вашем случае, invoice_id требуется, чтобы быть уникальным по причинам бизнеса, правильно? Как долго это? Вероятно, это хорошо, как ПК.

Какие ключи у вас были на столе, прежде чем вы попытались сделать ALTER? Когда вы изначально строите стол, у вас должно быть по крайней мере PRIMARY KEY. (Но уже слишком поздно, наверное.)

Просьба предоставить SHOW CREATE TABLE для каждого стола - мне нужно сделать слишком много догадок.

Добавление ключа суррогата (AUTO_INCREMENT) добавляет уровень косвенности для всех поисков; это может замедлить некоторые SELECTs (в дополнение к требованию изменения manySELECTs).

При добавлении вторичных индексов в таблицу основывайте их на том, что будет полезно для операторов SELECT, которые у вас есть. Я обсуждаю это в своем index cookbook. Предоставьте SELECTs здесь для дальнейшего обсуждения. Не слепо добавлять индекс для каждого столбца.

Это звучит как invoice_id должно быть PRIMARY KEY для invoice и INDEX в diagnose.

Если это практично, чтобы перезагрузить данные, объявить поля VARCHAR, не CHAR и имеют PRIMARY KEY(invoice_id) в invoice.

+0

Благодарим вас за проницательные входы и за вашу ссылку. Ссылка будет ссылкой для моей дальнейшей работы с БД. Позже я добавлю спецификацию таблицы. На данный момент: да, все ключи, о которых я упоминал, имеют точные 40 алфавитно-цифровых символов. Вот почему я использовал CHAR (40), иначе я бы использовал VARHCHAR (40). Проще обновить данные с помощью нового определения таблицы. Я использую utf8mb4, чтобы избежать каких-либо проблем с кодировкой. У меня есть немецкие умлаут французские акценты (но у ключей нет таких знаков). Да: _invoice_id_ уникален в ** счете ** (первичный ключ), но не в ** диагнозе ** (внешний ключ). – giordano

+0

Давайте посмотрим инструкцию 'LOAD DATA'; Я не понимаю, почему 'VARCHAR' не будет работать. Для французского и немецкого языков большинство символов - 1 байт в utf8 ut8mb4; акцентированные символы - 2 байта. Итак, ровно 40 символов в utf8mb4 занимает 160 байт для CHAR (40) 'и обычно менее 50 байт для' VARCHAR (40) '. –

+0

Даже если 'LOAD' должен перейти в' CHAR (40) ', вы можете быстро« ALTER »изменить столбцы на« VARCHAR (40) »и уменьшить размер таблицы в 3 раза. –