C, PHP, VB, .NET

Дневникът на Филип Петров


* FEDERATED таблици в MySQL

Публикувано на 21 май 2015 в раздел Бази от Данни.

Представете си, че имаме две различни системи, които работят с различни бази от данни, но желаем част от информацията в тези бази от данни да бъде споделена. Например имаме чат и форум – искаме когато някой се регистрира в чата, да бъде регистриран автоматично и във форума (и обратно). Тоест таблиците на двете бази от данни в по-голямата си част са различни, но една от тях – таблицата Users – трябва да бъде споделена между двете бази от данни.

Едно решение на този проблем е да пазим таблицата само в една от двете бази от данни – например в приложението на форума. Когато другото приложение – чата – има нужда да я достъпи, то ще отваря връзка до базата от данни на форума. Това обаче няма да е достатъчно гъвкаво, защото в базата от данни на чата реално няма да съществува таблица users и така ние няма да можем да свързваме други таблици с нея (foreign key constraints), както и не можем да правим заявки с JOIN с тази таблица (намира се в друга база от данни, която достъпваме с друга връзка).

На помощ ни идва Engine FEDERATED. Това е начин да добавяме таблици от други бази от данни (дори от други СУБД). За целта първо трябва да инструктираме MySQL, че ще може да използва такива таблици – в Windows това се отбелязва в C:\ProgramData\MySQL\MySQL Server 5.6\my.ini, а в Linux/BSD в /etc/my.cnf:

[mysqld]
federated

Сега ако приемем, че в базата от данни на форума съществува следната таблица:

CREATE TABLE users(
  id BIGINT UNSIGNED PRIMARY KEY,
  user VARCHAR(32) NOT NULL UNIQUE,
  pass VARCHAR(64) NOT NULL
)Engine=InnoDB;

то можем да „прехвърлим“ тази таблица в базата на чата по следния начин:

CREATE TABLE users(
  id BIGINT UNSIGNED PRIMARY KEY,
  user VARCHAR(32) NOT NULL UNIQUE,
  pass VARCHAR(64) NOT NULL
)Engine=FEDERATED
CONNECTION="mysql://dbuser:dbpass@dbhost:3306/forumdbname/users";

От гледна точка на чата, виртуалната таблица ще изглежда като съвсем нормална и ще можем да правим стандартните операции с нея, но всеки път, когато я достъпваме, реално СУБД ще отваря връзка с чуждата база от данни и ще изтегля необходимите данни от другото място.

Понякога е удачно да пазим и локално копие на данните, което да синхронизираме с отдалечената таблица. Например това може да се получи като и двете бази от данни имат следните две таблици със съответни тригери:

CREATE TABLE users(
  id BIGINT UNSIGNED PRIMARY KEY,
  user VARCHAR(32) NOT NULL UNIQUE,
  pass VARCHAR(64) NOT NULL
)Engine=InnoDB;

CREATE TABLE remote_users(
  id BIGINT UNSIGNED PRIMARY KEY,
  user VARCHAR(32) NOT NULL UNIQUE,
  pass VARCHAR(64) NOT NULL
)Engine=FEDERATED
CONNECTION="mysql://dbuser:dbpass@dbhost:3306/remotedbname/users";

CREATE TRIGGER remote_insert_users
BEFORE INSERT ON users FOR EACH ROW
BEGIN
   INSERT INTO remote_users(id, user, pass)
   VALUES (NEW.id, NEW.user, NEW.pass);
END;

CREATE TRIGGER remote_update_users
BEFORE UPDATE ON users FOR EACH ROW
BEGIN
  UPDATE remote_users
  SET user = NEW.user,
      pass = NEW.pass
  WHERE user = OLD.user;
END;

CREATE TRIGGER remote_delete_users
BEFORE DELETE ON users FOR EACH ROW
BEGIN
   DELETE FROM remote_users
   WHERE user = OLD.user;
END;

Естествено в двете бази стойностите на dbuser, dbpass, dbhost и remotedbname ще се различават. Изпълнено по този начин решението има едно голямо предимство – правенето на SELECT заявки ще е върху локалната таблица. Само Insert, Update и Delete ще изискват мрежови трафик между сървърите и ще изискват синхронизация. Голям недостатък обаче е липсата на ROLLBACK (FEDERATED таблиците НЕ могат да участват в трансакции!). Така ако заявката на remote сървъра пропадне двете таблици ще останат несинхронизирани. Поради тази причина FEDERATED таблиците не са много подходящи за точно този тип действия (когато ни трябва локално копие на данните, което да е гарантирано синхронизирано). Това може да го правите само ако по дизайн е допустимо да има известни разминавания между различните сървъри. Ако искате пълно синхронизиране на информацията, тогава е добре да се обърнете по-скоро към вариант за REPLICATION (ще бъде разгледан някога в следващи статии).

Ограничения и евентуални проблеми при FEDERATED Engine:

  • Отдалечената база от данни трябва да работи с MySQL СУБД;
  • Възможно е една Federated таблица да сочи към друга Federated таблица. В по-сложните комбинации трябва да внимавате от евентуален безкраен цикъл;
  • НЕ МОЖЕ ДА УЧАСТВА В ТРАНСАКЦИИ;
  • Отдалечената база от данни контролира индексите. Това може да доведе до по-честа нужда от изтегляне на цялата таблица локално и извършването на full table scan в случаите, когато отсрешната страна не успее да употреби индекси. Тези случаи водят до много мрежови трафик при големи таблици и много разхищение на оперативна памет;
  • Няма как да направите ALTER заявка върху отдалечена таблица. DROP заявките изтриват локалната виртуална таблица, а не отдалечената;
  • Не можете да използвате INSERT … ON DUPLICATE KEY UPDATE заявки, защото при дублиращ се ключ заявката ще връща грешка. Причината е невъзможността за участие в трансакция;
  • Една INSERT заявка с много редове се третира като серия от едноредови INSERT заявки, т.е. вмъкването на информация в отдалечена таблица в тези случаи е значително по-бавно;
  • Не се използва QUERY CACHE.

За повече информация вижте в сайта на MySQL.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*