Моят личен и професионален живот

2018-12-29

Разпознаване на функционални зависимости при групиране от MySQL

Ако сте използвали MySQL в миналото трябва да помните, че беше възможно по подразбиране да се сумира в заявки без GROUP BY клауза. Така можеше да напишете заявка като тази

SELECT D.dname, COUNT(E.empno) cnt
  FROM dept D,
       emp  E
 WHERE D.deptno = E.deptno;

най-вероятно с идеята да преброите служителите във всеки отдел. Обаче, резултата, който ще получите (без грешка) ще бъде:

+------------+-----+
| dname      | cnt |
+------------+-----+
| ACCOUNTING |  14 |
+------------+-----+

което просто е грешно и най-вероятно не това което искате в действителност. Такава заявка ще предизвика грешка в други бази данни (напр. Oracle ще даде ORA-00937: not a single-group group function, PostgreSQL ще каже SQL state: 42803 ERROR: column "d.dname" must appear in the GROUP BY clause or be used in an aggregate function, и т.н.).

Причината за това поведение беше SQL режима по подразбиране на сървъра и по-точно отсъствието на ONLY_FULL_GROUP_BY в списъка с режими. Има някои приложения (като Bugzilla и Cacti) които не ми позволяваха да разреша този режим на сървъра ми въпреки, че той беше отдавна препоръчван от някои (напр. спомням си представянията на Ronald Bradford от Есенната конференция на БГПО). Помня, че имах проблеми с тези приложения, така че сложих коментар в конфигурационния файл да не разрешавам ONLY_FULL_GROUP_BY. Трябва да призная, че не съм проверявал скоро, така че ситуацията може да се е подобрила, но с текущото състояние на Bugzilla е съмнително.

SQL режимите по подразбиране се промениха доста с последните версии на MySQL:
Единствената разлика в 8.0 в всъщност отсъствието на NO_AUTO_CREATE_USER, защото този режим беше премахнат след като бе обявен за остарял в предишните версии. Силно препоръчително е да придържате към тези режими по подразбиране особено при започване на ново приложение, за да не се налага да поправяте заявки и данни след това.

Когато ONLY_FULL_GROUP_BY беше разрешено с MySQL 5.7.5 (пуснат на 2014-09-25) Oracle се погрижи да изработи усъвършенствани функционални зависимости както Guilhem Bichot писа през Декември 2014. Усилието беше оценено от Markus Winand в неговата страхотна statiq One Giant Leap For SQL: MySQL 8.0 Released от Април 2018, който написа, че MySQL вече има "най-пълната проверка за функционални зависимости сред основните SQL бази данни". Да изследваме това, но преди това можете да се обърнете към Wikipedia за бърз преглед на определението за функционална зависимост. Казано просто Y е функционално зависим от X ако стойностите на X уникално определят стойностите на Y. Например стойностите на колоните в таблица са функционално зависими от първичния ключ, защото стойността му определя уникално всички други стойности в реда.
Вижте следния пример с първичен ключ. Това е заявката от горе, но с GROUP BY клауза:

SELECT D.dname, COUNT(E.empno) cnt
  FROM dept D,
       emp  E
 WHERE D.deptno = E.deptno
 GROUP BY D.deptno;

Правилна ли е тази заявка? Групирането е по D.deptno, но списъка с колони в SELECT съдържа само D.dname и сумиране по E.empno, така че е грешна, нали? Не и в MySQL 5.7 и по-нов с разрешен ONLY_FULL_GROUP_BY режим, така че старото правило да се слага всичко от GROUP BY клаузата в SELECT или да се ползва сумиране (т.е. без повече SQL-92 ограничения). Резултата е:

+------------+-----+
| dname      | cnt |
+------------+-----+
| ACCOUNTING |   3 |
| RESEARCH   |   5 |
| SALES      |   6 |
+------------+-----+

Защо така? MySQL правилно определя, че D.dname е функционално зависим от D.deptno, защото това е първичния ключ за dept таблицата. Същата заявка работи правилно и в PostgreSQL, но не и в Oracle и други основни SQL бази данни. MySQL може правилно да определя функционални зависимости също по уникални ключове, равенства в WHERE клауза или [LEFT] JOIN ON клаузи и от избрани изрази в тялото на изгледи и производни (derrived) таблици. Доста вълнуващо, нали? Гледайте да го използвате следващия път когато решите да пишете заявка с GROUP BY клауза.

За повече подробности, моля обърнете се към глава Detection of Functional Dependence в наръчника.

    2018-11-28

    Смяна на плана за изпълнение в MySQL 8.0

    Преди около 6 седмици в работата трябваше да напиша нова заявка представляваща доклад, защото страницата на едно приложение се зареждаше бавно (около 25 секунди). Оказа се, че име проблем с приложението, защото то първо изпълняваше сравнително бавна заявка (отнемаща около 6 секунди) и тогава сравнително бърза заявка за всеки ред върнат от първата заявка. Втората заявка отнемаше между 0.3 и 0.5 секунди за изпълнение, но се изпълваше около 60 пъти, така че закъснението се натрупваше и обясни забавянето на страницата.
    Реших да предоставя една единствена заявка създаваща целия резултат, така че трябваше да съединя 6 таблица. Една таблица (msg_progs) имаше само 13 реда, други две имаха само 64 реда (bldenv и prjprocstat), а друга само около 100 реда (p) тези четирите нямаха тенденция да растат много повече. Имаше една таблица с няколко десетки хиляди реда (m) и друга с няколко стотин хиляди реда (mtp), които със сигурност щяха да растат всеки ден. За да подобря избирателността във втората по големина таблица (m) създадох съставен индекс по три колони използвани от заявката, но проблема беше, че все още се избираха повечето от данните в таблицата. Така приключих с заявка изпълняваща се за 6-7 секунди, което беше доста по-приемливо от първоначалните 25 секунди. Не мога да разкрия всички подробности, но направих снимка на плана за изпълнение и смятам, че няма проблем да го публикувам.
    Query explain plan in MySQL 5.7.20
    Забележка: MySQL Workbench показва страхотно планове за изпълнение графично (забележете линиите свърващи различните операции - колкото по-голям е броя на редовете толкова по-дебела е линията). Текстовите планове за изпълнение са вече минало, нали?

    Това беше до преди 3 седмици когато надградихме до MySQL 8.0.13 (от 5.7.20). Същата заявка и в същата база започна да се изпълнява по 24 секунди. Когато проверих плана за изпълнение той се беше променил (виж отдолу).
    Original explain plan in MySQL 8.0
    Мисля, че можете лесно да забележите, че реда на съединяване се е променил. Преди втората по големина таблица се взимаше в предвид в първия вложен цикъл, след това най-голямата таблица и накрая по-малките таблици. Сега е обратното, защото оптимизатора първо взема в предвид по-малките таблици и само тогава по-големите. Можех да използвам подсказка, за да оправя реда на съединяване (напр. JOIN_ORDER), но забелязах, че ако пресъздам съставния индекс по само две от колоните (които всъщност дават по-добра избирателност) оптимизатора избира различен план, но заявката все още се изпълвана за около 14 секунди. Накрая реших да премахна една от таблиците в съединението (най-малката msg_progs само с 13 реда), което накара оптимизатора да избере друг план за изпълнение (тук отдолу) и заявката вече се изпълнява за около 4 секунди.
    Finaly explain plan in MySQL 8.0
    Не съм сигурен от къде идва тази разлика освен от сървъра, но не мога да обвинявам без доказателство (напр. препратка към наръчника, която обяснява разликата), което за съжаление нямах време да търся. Ако знаете причината за смяната на плана за изпълнение в MySQL 8.0 моля уведомете ме.
    Ситуацията ми напомни за базата на Oracle където след всяка главна версия имахме заявки с променен план за изпълнение и трябваше да използваме подсказки или други номера, за да ги забързаме отново. Изглежда да няма разлика при MySQL днес.
    Обновяване 2018-12-17: Направих прибързано заключение по-горе, защото промяната на плана се случи (или поне беше забелязана) след надграждането на сървъра. Обаче, както се оказа истинската причина беше броя на редовете в таблиците m и mtp заради който сървъра избираше различен план на изпълнение. Открихме това експериментирайки с различни по обем набори с данни.

    2018-11-27

    Игра на авторитети

    В управленската теория и практика има случаи в които е необходимо да се използва авторитет (напр. за налагане на крайни срокове, за решаване на конфликти, и т.н.). Само че, докато разбирам нуждата, наистина не разбирам управители на които се налага да използват авторитета си когато са останали без всякакъв друг аргумент. Имал съм ситуации в миналото когато авторитет е бил необходим, но винаги съм подхождал с неохота и никога не съм ползвал без сериозен аргумент (което е било любезно признавано). Това което имам в предвид, е че не мога просто да наложа нещо на някого ако нямам добра причини за това и ако не съм го оправдал пред засегнатите страни.
    Въпросът е, че понякога аргументите на страните в обсъждане могат да изглеждат еднакво важни и действителни, така че нуждата от арбитраж и използването на авторитет може да се неизбежни. Един начин да се реши това е да се основат следващите аргументи на предишни факти като преди това записани обсъждания, споразумения, процедури и практики относно същата или сродна материя. Ами ако другата страна просто не приеме допълнителните аргументи? Е, наистина не знам, но мисля, че това говори достатъчно за другата страна. Във фирмените общества без добро управление на документацията и постоянна смяна на авторитетите знанието бързо се губи във времето. Нови правила и процедури се създават всеки ден, защото никой не я наясно или не желае да приеме това което е било определено в миналото. Така се създават легенди.

    2018-11-15

    Маскиране на данни и анонимизация в изданието за обществото на MySQL

    Oracle наскоро въведе функционалност за маскиране на данни в MySQL, но тя е достъпна само в изданието за предприятия (виж MySQL Enterprise Data Masking and De-Identification в наръчника). Не съм клиент, но съм запознат с идеята както и със съхранени процедури, така че реших да се опитам да емулирам това което MySQL са изработили за тяхното издание за предприятия на базата.

    Започнах с четене на наръчника, после прегледах форматите за номера на кредитна карта и социална осигурвока, за да изляза накрая с просто изпълнение изработено тази вечер. Изработих само функциите за маскиране с общо и специално предназначение и функциите за създаване на случайни данни (напр. е-поща, номер на карта за разплащания, номер на социална осигуровка и телефонен номер в САЩ). Имам допълнителна функция gen_rnd_string за създаване на низ от случайни символи с дадена дължина (само знаци от английската азбука по подразбиране). Направих няколко теста и резултатите изглеждат обещаващо, но трябва да пробвам повече и вероятно да създавам по-добри данни, които евентуално да минават проверка, защото приложение използващо случайно създадени данни може лесно да се счупи ако не може да ги провери. Остава ми да изработя функциите за създаване на случайни данни с използване на речници за които смятам, че мога да ползвам LOAD DATA INFILE и CREATE TEMPORARY TABLE за зараждане на речник.

    Това е просто моята идея за това как може да бъде изработено маскиране на данни и анонимизация дори в изданието за обществото на MySQL и като съхранени процедури, защото реализацията на MySQL се основава на потребителски дефинирани функции (UDF). Чудя се защо са избрали този подход и отдолу опита ми да отгатна възможните отговори:
    • Видимост: Потребителски дефинираната функция има глобална видимост, така че може да бъде извикана без името на схемата отпред като всяка друга вградена функция. Моята реализация трябва да бъде заредена в схема и така всяка функция ще трябва да се вика с име на схемата отпред.
    • Подразбрани аргументи: MySQL все още не поддържа подразбрани аргументи за съхранени процедури, но това е възможно за потребителски дефинирани функции тъй като те могат да се написани само "на C или C++ (или друг език, който може да използва C конвенция на извикванията)". Функциите за маскиране с общо предназначение mask_inner и mask_outer приемат незадължителен аргумент за символа с който да се маскира. В реализация със съхранени процедури това може да стане само с потребителски дефинирана променлива. Ще изработя това по-късно.
    • Скриване на подробностите по изработката: Потребителски дефинираните функции скриват изработката на MySQL в двоичния файл на споделената библиотека. Изходния код на съхранените процедури може лесно да бъде разгледан от потребител с достатъчно права (напр. администратор). До колкото ми е известно MySQL не предлага инструмент за разбъркване на кода както Oracle (виж Obfuscating PL/SQL Source Code). Отделно от това наръчника не предоставя достатъчно подробности за възможните стойности от функциите за създаване на данни.
    • Сигурност: Това може да се отнася до начина по който сървъра управлява паметта за потребителски дефинираните функции и съхранените процедури, но това е твърде навътре в нещата.
    • Производителност: Потребителски дефинираните функции по предположение трябва да имат по-добра производителност в сравнение със съхранените процедури, защото първите са извиквания на функции в компилирана за съответната система съхранена библиотека, а вторите се интерпретират от сървъра при всяко извикване.
    Нетърпелив съм да обсъдя това утре на Есенната конференция на БГПО 2018 където ще има представяне на точно същата тема. Ще обновя публикацията или ще напиша нова след събитието.

    Обновяване 2018-11-16 19:01 EET: BGOUG конференцията потвърди представите ми за паричните, поради които маскирането на данни е изработено като UDF функции. Една от цитираните причини беше точно "производителност".

    Обновяване 2018-11-18 19:51 EET: След като си поиграх още малко и опитах да направя речниковите функции днес, се сблъсках с две ограничения, за които не бях помислил преди това. Първото ограничение е невъзможността за използване на подготвени изрази във функция (т.е. от главата Prepared SQL Statement Syntax в наръчника "SQL syntax for prepared statements can be used within stored procedures, but not in stored functions or triggers"). Второто ограничение е невъзможността за използване на LOAD DATA INFILE като подготвен израз (виж секция SQL Syntax Allowed in Prepared Statements в наръчника). Първото ограничение означава, че речниковите функции могат да бъдат изработени само като процедури. Второто ограничение означава, че е невъзможно да се зареди речника от файл, така че изработката на функция gen_dictionary_load не може да бъде завършено - тя може да създаде временната таблица за речника, но не може да го зареди. Все пак направих процедурите и успях да създам случайни градове в САЩ. Също така проверих производителността с gen_rnd_pan функцията, тъй като тя прави както създаване на случаен низ от цифри, така и изчисление на числото на Лун. На моя MySQL 5.7 сървър работещ върху Intel Pentium G3420 @ 3.2 GHz с 8 GB DDR3 RAM пуснах SELECT BENCHMARK(count, gen_rnd_pan()) и резултата за различен брой повторения беше следния:
    • 1000 пъти - 0.28 секунди;
    • 10000 пъти - 3.13 секунди;
    • 100000 пъти - 31.41 секунди;
    • 1000000 пъти - 278.19 секунди.
    Освен ако MySQL не премахне ограниченията за мен темата е приключена. Мога да се опитам да направя функциите за маскиране на данни като UDF както MySQL ако намеря време и ако имам истинска нужда.

    2018-10-23

    Нови възможности за разработчици в MySQL 8.0.13

    Ах, каква седмица вече и още не е приключила! Първо, Oracle пуснаха Oracle XE 18c (както писах в Неделя), а вчера (22-ри Октомври) пристигна MySQL 8.0.13 заедно (както вече обичайно) с целия флот (Router, Shell, Workbench и C++/J/ODBC/NET/Python/Node.js Connectors). Бях нетърпелив да прочета журнала с промените и както посочената статия от блога на MySQL Server също подсказва има някои интересни нови възможности за дизайнери и разработчици. Тук отдолу е моя избор и няколко думи за надграждане от 8.0.12.

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

    Вече е възможно да има стойности по подразбиране като функция или израз. Това е важна нова възможност. Преди само буквални стойности бяха позволени, което беше доста ограничаващо. Премахването на това ограничение означава, че вече е възможно:
    • да се създават UUID стойности по подразбиране (с използването на DEFAULT (uuid_to_bin(uuid())) например);
    • да се създават стойности по подразбиране за геометрични типове данни (с използването на DEFAULT (POINT(0,0)) или DEFAULT (ST_PointFromText('POINT(42.69751 23.32415)', 4326)) например);
    • да се създават стойности по подразбиране за JSON колони (с използването на DEFAULT (JSON_ARRAY()) или DEFAULT ('[]') например); и
    • други сложни стойности (като DEFAULT (CURRENT_DATE + INTERVAL 1 DAY) or DEFAULT (PI() * POW(r, 2)) например) с използването на функция или функции в израз.
    Забележка: Моля, обърнете внимание на скобите обграждащи израза в DEFAULT (виж Handling of Explicit Defaults as of MySQL 8.0.13 в наръчника). MySQL Workbench 8.0.13 отново има някои проблеми с синтактичния разбор на новия синтаксис (виж екранната снима отдолу), така че отворих бъг 92900 и той вече беше потвърден:

    MySQL Workbench 8.0.13 грешка с изрази по подразбиране


    Пробвах новата функционалност със следното:

    CREATE TABLE def_expr (
      id        INT           NOT NULL AUTO_INCREMENT,
      uuid_def  BINARY(16)    DEFAULT (uuid_to_bin(uuid())),
      geo_def   POINT         DEFAULT (Point(0,0)),
      geo_def2  GEOMETRY      DEFAULT (ST_PointFromText('POINT(42.69751 23.32415)', 4326)),
      json_def  JSON          DEFAULT (JSON_ARRAY()),
      json_def2 JSON          DEFAULT ('[]') /* this works too */,
      tomorrow  DATE          DEFAULT (CURDATE() + INTERVAL 1 DAY),
      radius    INT           DEFAULT (FLOOR(1 + (RAND() * 10))),
      area      DECIMAL(10,3) DEFAULT (ROUND(PI() * POW(radius, 2), 3)),

      PRIMARY KEY (id),
      UNIQUE INDEX id_UNIQUE (id ASC) VISIBLE
    );



    След това вмъкнах две пробни линии и получих следните резултати:

    INSERT INTO def_expr VALUES (); /* x 2 */

    SELECT id,
           bin_to_uuid(uuid_def) uuid_def,
           ST_AsText(geo_def)    geo_def,
           ST_AsText(geo_def2)   geo_def2,
           json_def, json_def2,
           tomorrow, radius, area
      FROM def_expr;


    +----+--------------------------------------+------------+--------------------------+----------+-----------+------------+--------+---------+
    | id | uuid_def                             | geo_def    | geo_def2                 | json_def | json_def2 | tomorrow   | radius | area    |
    +----+--------------------------------------+------------+--------------------------+----------+-----------+------------+--------+---------+
    |  1 | a2747ee0-d6ee-11e8-b02e-02004c4f4f50 | POINT(0 0) | POINT(42.69751 23.32415) | []       | []        | 2018-10-24 |      2 |  12.566 |
    |  2 | a2ff920b-d6ee-11e8-b02e-02004c4f4f50 | POINT(0 0) | POINT(42.69751 23.32415) | []       | []        | 2018-10-24 |     10 | 314.159 |
    +----+--------------------------------------+------------+--------------------------+----------+-----------+------------+--------+---------+
    2 rows in set (0.0021 sec)


    Яко, нали? Нетърпелив съм да го пробвам с проектите ми.

    Функционални SQL индекси


    Вече можете да имате функционални индекси (виж Functional Key Parts в наръчника), което означава, че индекса се изгражда от стойности на изрази, вместо стойности на колони или началната част на стойности на колони. С други думи можете да индексирате стойности, които не са съхранени в таблица, което смятам, че може да бъде доста мощно в определени случаи. В съставни индекси с няколко части на ключа можете да смесвате функционални и нефункционални (обикновени) части. Функционалните части на ключа са реализирани, чрез скрити виртуални породени колони (виж CREATE TABLE and Generated Columns в наръчника), които са налични от MySQL 5.7.6 (от 2015-03-09). Това също така значи, че функционалните части на ключа имат същите ограничения (т.е. детерминирани вградени функции и оператори са разрешени, но подзаявки, параметри, променливи, съхранени и потребителски функци не са разрешени).
    За да пробвам новата функционалност се сетих, че IP адреси обичайно се съхраняват като текст в базите и после се четат и разбиват, но адреса може да се представи като целочислена стойност (без знак), което изисква само 4 байта. Така, че използвах следното:

    CREATE TABLE func_index (
      id        INT        NOT NULL AUTO_INCREMENT,
      ipaddr4   INT UNSIGNED /* 4 bytes */,

      PRIMARY KEY (id),
      UNIQUE INDEX id_UNIQUE (id ASC) VISIBLE,
      INDEX func_idx ((INET_NTOA(ipaddr4)))
    );

    Забележка: Моля, обърнете внимание на скобите обграждащи израза. Без тях ще има код 1064 (синтактична грешка). Очаквано MySQL Workbench 8.0.13 не е готов за новия синтаксис, така че отворих бъг 92908 и той също вече беше потвърден.

    MySQL Workbench 8.0.13 грешка с функционален индекс

    След това вмъкнах една линия и пуснах обяснение на плана за изпълнение на двете SELECT заявки отдолу:

    INSERT INTO func_index (ipaddr4) VALUES (INET_ATON('192.168.1.1'));

    SELECT * FROM func_index WHERE ipaddr4 = INET_ATON('192.168.1.1');
    SELECT * FROM func_index WHERE INET_NTOA(ipaddr4) = '192.168.1.1';

    Първата ще доведе до пълно сканиране на таблицата, докато втората ще доведе до четене на функционалния индекс func_idx. За да може заявката да използва индекса е важно израза в WHERE клаузата да съвпада с този в дефиницията на индекса.

    Възможност за забрана на създаването на таблици без първичен ключ

    Вече има системна променлива sql_require_primary_key, която предотвратява създаването или промяната на таблици без първичен ключ ако е зададена. В този случай CREATE или ALTER зявки вече ще пропадат с код за грешка 3750 (виж също SQL състояние ER_TABLE_WITHOUT_PK).
    Пробвах тази нова възможност задавайки глобалната променлива в сесия така:

    SET GLOBAL sql_require_primary_key = ON;

    но успях да създам таблица без първичен ключ. Трябва да проверя отново утре и евентуално да докладвам бъг. Задаването на променливата в my.ini и след рестартиране на сървъра работи както трябва:

    SQL> CREATE TABLE tab_no_pk (test INT);
    ERROR: 3750: Unable to create a table without PK, when system variable 'sql_require_primary_key' is set. Add a PK to the table or unset this variable to avoid this message. Note that tables without PK can cause performance problems in row-based replication, so please consult your DBA before changing this setting.

    Вече ще си почина от разработчици незапознати с релационната теория :-)

    Геометрична трансформация

    Вече е възможно да се преобразува геометрия от една пространствена референтна система (SRS) към друга с вградената функция ST_Transform, която приема като втори аргумент целевата SRS. Нямам голям интерес към GIS, така че не съм я пробвал, но изглеждаше, че си струва да бъде спомената.

    Няколко думи за надграждането (от 8.0.12)

    Надграждането на Windows инсталацията ми беше безпроблемно с MySQL Installer за Windows. Обаче, имах проблем с Linux инсталацията ми, която съдържа повече бази данни. Сървъра не можеше да стартира и в журнала с грешки намерих грешки като следната:

    2018-10-23T12:47:49.627732Z 1 [ERROR] [MY-013235] [Server] Error in parsing View 'db'.'aView' during upgrade. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'desc' at line 1

    Отворих бъг 92898 за това и проблема вече беше обяснен от поддръжката с несъвместима промяна (виж SQL Syntax Notes от бележките към версията). Почти сигурен съм, че четох някъде за това, че ASC или DESC ключовите думи за GROUP BY клаузата са обявени за архаични и наистина не помня защо съм използвал такъв синтаксис, но ме свари неподготвен, така че се наложи да надградя заявката на изгледите.

    Има доста повече в MySQL 8.0.13 и горещо ви препоръчвам да прегледате статията The MySQL 8.0.13 Maintenance Release is Generally Available и бележките към версията, след което да изследвате сами.

      2018-10-21

      Първи впечатления от Oracle Database XE 18c опитвайки се да я инсталирам на Fedora 28 и Oracle Linux 7

      Oracle пусна Oracle Database Express Edition (или по-известна като XE) на 19 Октомври 2018. Тази дата също така се пада и рождения ми ден, така че какъв страхотен подарък! Нека да вземем да отворим подаръка и да го пробваме!
      Чакането за Oracle XE 18c беше дълго като предишната версия (основана на 11g Release 2) се появи преди 7 години (на 24 Септември 2011) а версия основана на Oracle 12c никога не се появи. Използвах XE на Fedora откакто 11g се появи през 2011, но с новите версии на Fedora това стана невъзможно. Базата се държеше странно и не можеше да се ползва след рестарт, но така и не намерих време да разследвам в дълбочина тези проблеми. Така обмислях да пробвам Oracle Linux вместо това (виж Which OS is “the best” for Oracle? за експертно мнение).

      Fedora 28

      Понеже нямам достатъчно място във виртуалната машина изтеглих RPM-ите на сървър и пробвах да ги инсталирам от NFS дял следвайки инструкциите в Quick Start:

      [root@fedora ~]# yum -y localinstall /mnt/vm/oracle-database-preinstall-18c-1.0-1.el7.x86_64.rpm
      Last metadata expiration check: 2:01:29 ago on Sun 21 Oct 2018 11:07:06 AM EEST.
      Error:
       Problem: conflicting requests
        - nothing provides compat-libcap1 needed by oracle-database-preinstall-18c-1.0-1.el7.x86_64



      Хмм... Просто липсва необходимия пакет compat-libcap1, но защо не бива инсталиран автоматично?

      [root@fedora ~]# yum install compat-libcap1
      Last metadata expiration check: 1:24:06 ago on Sun 21 Oct 2018 11:07:06 AM EEST.
      No match for argument: compat-libcap1
      Error: Unable to find a match


      Това е странно, но Fedora не предоставя този пакет. Открих го в CentOS хранилището (праяка връзка за изтегляне) и след инсталиране на compat-libcap1 preinstall RPM-а се инсталира успешно. Обаче, инсталацията на базата пропадна:

      [root@fedora ~]# yum -y localinstall /mnt/vm/oracle-database-xe-18c-1.0-1.x86_64.rpm
      Last metadata expiration check: 2:16:29 ago on Sun 21 Oct 2018 11:07:06 AM EEST.
      Dependencies resolved.
      ==========================================================
       Package                Arch   Version Repository    Size
      ==========================================================
      Installing:
       oracle-database-xe-18c x86_64 1.0-1   @commandline 2.4 G

      Transaction Summary
      ==========================================================
      Install  1 Package

      Total size: 2.4 G
      Installed size: 5.2 G
      Downloading Packages:
      Running transaction check
      Transaction check succeeded.
      Running transaction test
      Error: Transaction check error:
        package oracle-database-xe-18c-1.0-1.x86_64 does not verify: no digest
        installing package oracle-database-xe-18c-1.0-1.x86_64 needs 2472MB on the / filesystem


      Error Summary
      -------------
      Disk Requirements:
         At least 2472MB more space needed on the / filesystem.


      Явно изискванията към дисковото пространство са се повишили, защото преди инсталирах XE 11gR2 на същата виртуална машина. Трябваше да уголемя диска и разширя дяла. Обаче, проблема Error: Transaction check error: package oracle-database-xe-18c-1.0-1.x86_64 does not verify: no digest остана, затова писах във форума (виж нишка 14969247).

      За да се справя с това използвах следната команда. Но за да проработи трябваше да инсталирам също така libnsl (т.е. dnf install libnsl) и увелича още веднъж дисковото пространство. Явно инсталацията на RPM-а изисква около 5,2 ГБ.

      [root@fedora ~]# rpm -i --nodigest /mnt/vm/oracle-database-xe-18c-1.0-1.x86_64.rpm
      warning: /mnt/vm/oracle-database-xe-18c-1.0-1.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID ec551f03: NOKEY
      [INFO] Executing post installation scripts...
      [INFO] Oracle home installed successfully and ready to be configured.
      To configure Oracle Database XE, optionally modify the parameters in '/etc/sysconfig/oracle-xe-18c.conf' and then execute '/etc/init.d/oracle-xe-18c configure' as root.


      Така идва време за конфигурация. За създаването на базата са необходими още 4,5 ГБ дисково пространство.

      [root@fedora ~]# /etc/init.d/oracle-xe-18c configure
      Specify a password to be used for database accounts. Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts:
      Confirm the password:
      Configuring Oracle Listener.
      Listener configuration succeeded.
      Configuring Oracle Database XE.
      [WARNING] [DBT-11209] Current available memory is less than the required available memory (796MB) for creating the database.
         CAUSE: Following nodes do not have required available memory :
       Node:fedora            Available memory:471.8672MB (483192.0KB)

      Enter SYS user password:
      *************
      Enter SYSTEM user password:
      *************
      Enter PDBADMIN User Password:
      **************
      Prepare for db operation
      7% complete
      Copying database files
      29% complete
      Creating and starting Oracle instance
      30% complete
      31% complete
      34% complete
      38% complete
      41% complete
      43% complete
      Completing Database Creation
      47% complete
      50% complete
      Creating Pluggable Databases
      54% complete
      71% complete
      Executing Post Configuration Actions
      93% complete
      Running Custom Scripts
      100% complete
      Database creation complete. For details check the logfiles at:
       /opt/oracle/cfgtoollogs/dbca/XE.
      Database Information:
      Global Database Name:XE
      System Identifier(SID):XE
      Look at the log file "/opt/oracle/cfgtoollogs/dbca/XE/XE.log" for further details.

      Connect to Oracle Database using one of the connect strings:
           Pluggable database: fedora:1539/XEPDB1
           Multitenant container database: fedora:1539
      Use https://localhost:5500/em to access Oracle Enterprise Manager for Oracle Database XE


      Забележка: Ако получите  Listener configuration failed. Check log '/opt/oracle/cfgtoollogs/netca/netca_configure_out.log' и в журналния файла присъства линията No valid IP Address returned for the host fedora просто задайте пълното име на машината заедно с домейна в /etc/hostname пуснете конфигурацията отново.

      Същата процедура е приложима към Fedora 29.

      Oracle Linux Server 7.5

      Инсталацията на preinstall RPM-а става гладко:


      [root@oracle ~]# yum -y localinstall /mnt/vm/oracle-database-preinstall-18c-1.0-1.el7.x86_64.rpm
      Loaded plugins: ulninfo
      Examining /mnt/vm/oracle-database-preinstall-18c-1.0-1.el7.x86_64.rpm: oracle-database-preinstall-18c-1.0-1.el7.x86_64
      Marking /mnt/vm/oracle-database-preinstall-18c-1.0-1.el7.x86_64.rpm to be installed
      Resolving Dependencies
      --> Running transaction check
      ---> Package oracle-database-preinstall-18c.x86_64 0:1.0-1.el6 will be installed
      ...
      --> Processing Dependency: compat-libcap1 for package: oracle-database-preinstall-18c-1.0-1.el6.x86_64
      ...
      Dependencies Resolved

      ====================================================================
       Package                         Arch   Version     Repository Size
      ====================================================================
      Installing:                                                  
       oracle-database-preinstall-18c  x86_64 1.0-1.el7   /oracle... 55 k
      Installing for dependencies:                                 
      ...                                                          
       compat-libcap1                  x86_64 1.10-7.el7  ol7_latest 17 k
      ...
      Install  1 Package (+37 Dependent packages)
      ...
      Installed:
        oracle-database-preinstall-18c.x86_64 0:1.0-1.el7

      Dependency Installed:
      compat-libcap1.x86_64 0:1.10-7.el7
      ...
      Complete!


      Зависимостта от compat-libcap1 беше лесно разрешена както и 36 други зависимости, защото инсталацията ми на Oracle Linux е нова и нямам много инсталирани пакети все още. Инсталацията на RPM-а с базата също стана без проблеми:

      [root@oracle ~]# yum -y localinstall /mnt/vm/oracle-database-xe-18c-1.0-1.x86_64.rpm
      Loaded plugins: ulninfo
      Examining /mnt/vm/oracle-database-xe-18c-1.0-1.x86_64.rpm: oracle-database-xe-18c-1.0-1.x86_64
      Marking /mnt/vm/oracle-database-xe-18c-1.0-1.x86_64.rpm to be installed
      Resolving Dependencies
      --> Running transaction check
      ---> Package oracle-database-xe-18c.x86_64 0:1.0-1 will be installed
      --> Finished Dependency Resolution

      Dependencies Resolved

      ========================================================
       Package                 Arch   Version Repository Size
      ========================================================
      Installing:
       oracle-database-xe-18c  x86_64 1.0-1   /oracle... 5.2 G

      Transaction Summary
      ========================================================
      Install  1 Package

      Total size: 5.2 G
      Installed size: 5.2 G
      Downloading packages:
      Running transaction check
      Running transaction test
      Transaction test succeeded
      Running transaction
        Installing : oracle-database-xe-18c-1.0-1.x86_64  1/1
      [INFO] Executing post installation scripts...
      [INFO] Oracle home installed successfully and ready to be configured.
      To configure Oracle Database XE, optionally modify the parameters in '/etc/sysconfig/oracle-xe-18c.conf' and then execute '/etc/init.d/oracle-xe-18c configure' as root.
        Verifying  : oracle-database-xe-18c-1.0-1.x86_64  1/1

      Installed:
        oracle-database-xe-18c.x86_64 0:1.0-1

      Complete!


      И явно около 5.2 GB е мястото, което наистина е необходимо за самия софтуер, защото преди инсталацията имах горе долу толкова повече свободно пространство на дяла. Да се опитаме да конфигурираме базата:

      [root@oracle ~]# /etc/init.d/oracle-xe-18c configure
      The location '/opt/oracle' specified for database files has insufficient space.
      Database creation needs at least '4.5GB' disk space.
      Specify a different database file destination that has enough space in the configuration file '/etc/sysconfig/oracle-xe-18c.conf'.


      Аха... значи изискванията към дисковото пространство са горе долу същите като на Standard Edition on Linux. След преоразмеряване на диска и уголемяване на дяла конфигурацията минава успешно за около 10 минути:

      [root@oracle ~]# /etc/init.d/oracle-xe-18c configure
      Specify a password to be used for database accounts. Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts:
      Confirm the password:
      Configuring Oracle Listener.
      Listener configuration succeeded.
      Configuring Oracle Database XE.
      Enter SYS user password:
      *************
      Enter SYSTEM user password:
      ***************
      Enter PDBADMIN User Password:
      ***********
      Prepare for db operation
      7% complete
      Copying database files
      29% complete
      Creating and starting Oracle instance
      30% complete
      31% complete
      34% complete
      38% complete
      41% complete
      43% complete
      Completing Database Creation
      47% complete
      50% complete
      Creating Pluggable Databases
      54% complete
      71% complete
      Executing Post Configuration Actions
      93% complete
      Running Custom Scripts
      100% complete
      Database creation complete. For details check the logfiles at:
       /opt/oracle/cfgtoollogs/dbca/XE.
      Database Information:
      Global Database Name:XE
      System Identifier(SID):XE
      Look at the log file "/opt/oracle/cfgtoollogs/dbca/XE/XE.log" for further details.

      Connect to Oracle Database using one of the connect strings:
           Pluggable database: oracle.sotirov-bg.net/XEPDB1
           Multitenant container database: oracle.sotirov-bg.net
      Use https://localhost:5500/em to access Oracle Enterprise Manager for Oracle Database XE


      Дори след успешна инсталация и конфигурация има нужда от две ръчни стъпки:
      • Задаване на променливи на средата. За това просто добавих следното в /etc/profile:
      export ORACLE_HOME=/opt/oracle/product/18c/dbhomeXE
      export ORACLE_SID=XE
      pathmunge $ORACLE_HOME/bin after

      • Разрешаване стартирането на базата със системата. За това използвах скрипта предоставен по-подразбиране в /etc/init.d/oracle-xe-18c и пуснах следното:
      chkconfig --add oracle-xe-18c; chkconfig oracle-xe-18c on

      systemctl enable oracle-xe-18c
      • Разрешаване на достъп по мрежата. За това е нужно да се разреши стандартния порт на слушателя 1521 на защитната стена:
      firewall-cmd --permanent --zone=public --add-port=1521/tcp
      systemctl reload firewalld

      Време за връзка с базата:

      [root@oracle ~]# sqlplus sys/password@//localhost:1521/XE as sysdba

      SQL*Plus: Release 18.0.0.0.0 - Production on Sun Oct 21 19:16:35 2018
      Version 18.4.0.0.0

      Copyright (c) 1982, 2018, Oracle.  All rights reserved.

      Connected to:
      Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
      Version 18.4.0.0.0

      SQL>


      Ура! Сега след като базата е инсталирана и достъпна е време да заредя малко данни и да почвам да експериментирам.

      2018-08-22

      LibreOffice 6.1 и замяна на именовани параметри

      Наскоро надградих до LibreOffice 6.1 нетърпелив да пробвам новите възможности и подобрения. Обаче, скоро забелязах, че всичките ми под формуляри в Base са счупени. Това са суб формуляри  изпълняващи SQL заявки като:

      SELECT id, name FROM persons

      Така че да мога да получа допълнителна информация от свързани таблици с напасване между главни и подчинени полета. Явно в по-ранни версии Base е пренаписвал заявката, но случая вече не е такъв. Ще получите грешки като:
      • Зареждането на данните бе невъзможно.
      • Състояние на SQL: 07009 Невалиден индекс на дескриптор.
      • Опитахте се да зададете параметър на позиция 1, но броят на разрешените параметри е 0. Една възможна причина е, че свойството „ParameterNameSubstitution“ не е със стойност TRUE в източника на данни.
      Бързо отворих бележките към версията и открих каквото бях пропуснал преди:

      Base
      • The ODBC, JDBC and Firebird SDBC drivers/bridges previously applied named parameter substitution (for ODBC and JDBC: when enabled) to all SQL commands, including those that were tagged in the GUI as "execute SQL command directly", thereby not preserving the SQL command exactly as typed. Named parameter substitution now is applied only to SQL queries that are generated from a LibreOffice SQL parse tree, leaving "execute SQL command directly" commands completely untouched.
      Така че решението е да се пренапишат заявките на под формуляра ето така (което е синтаксиса за неименувани параметри използван от MySQL):

      SELECT name FROM persons WHERE id = ?

      Или с други думи явно да се напише параметъра в заявката.

      2018-07-11

      Защо зареждането на данни с MySQL Workbench е толкова бавно?

      Наскоро започнах малък личен проект за статистики за състезанието за издръжливост 24-те часа на Льо Ман на което съм фен. Започнах със събирането на данни и за зареждането им започнах да използвам функционалността в MySQL Workbench. Функционалността е достъпна от контекстното меню на таблица - щракате с десния бутон върху таблица и след това на елемента "Table Data Import Wizard". Това е доста изпипана възможност, защото ви позволява:
      • първо да изберете локален файл;
      • после, да изберете местоназначение - или съществуваща таблица (и да я изтриете цялата ако е нужно) или нова таблица;
      • после, да зададете настройки (напр. възможности за CSV като разделители на колони и редове и символ за ограждане на стойности), кодиране на файла и карта на колоните;
      • накрая да започнете зареждането и да следите за грешки (печата се съобщения за всеки ред от входния файл).
      Обаче, с нарастващия брой линии в CSV файла, забелязах че зареждането на данни става по-бавно и по-бавно (не обърнах много внимание първоначално), така че за около 4500 линии вече отнема около 5 минути (!) в локална мрежа и на сървър, който не е толкова натоварен с работа. Не мога да си представя ако трябва да заредя стотици хиляди или дори милиони редове по този начин.
      Пробвах същото с LOAD DATA INFILE и същите данни бяха заредени за около 1 секунда, дори при положение, че имам някои тригери на таблицата проверяващи новите въвеждани данни. Разликата е доста очевидна. Така, че защо зареждането на данни с MySQL Workbench е толкова бавно в сравнение с LOAD DATA INFILE заявката?
      С проверка на общия журнал на сървъра разликата става незабавно явна - MySQL Workbench създава INSERT заявка за всеки ред от входния файл и изпълнява тези заявки последователно една по една. Това е доста скъпо и време отнемащо особено по мрежата (виж Optimizing INSERT Statements).
      Но защо това е така? Две възможни обяснения:
      1. LOAD DATA INFILE заявката изисква файла да бъде достъпен за сървъра (т.е. на локална файлова система достъпна за сървъра). Обаче, с ключовата дума LOCAL клиента може да прехвърли файла на сървъра, така че сървъра да може да го чете. Натоварването в този случай ще е прехвърлянето на файла по мрежата. Това обаче изисква и сървъра и клиента да имат разрешена способност за зареждане на локални данни (за сървъра виж системната променлива local_infile, а за клиента е с конфигурационна променлива ENABLED_LOCAL_INFILE на CMake). Затова, въпреки че имам тази способност разрешена на сървъра явно тя е забранена в MySQL клиента използван от Workbench, защото опитвайки се да изпълня LOAD DATA INFILE с ключовата дума LOCAL дава Error Code: 1148. The used command is not allowed with this MySQL version (виж повече в Security Issues with LOAD DATA LOCAL).
      2. Използване на INSERT заявка с множество VALUES списъци за вмъкване на много редове наведнъж няма да даде възможност на Workbench да предоставя информация за всеки обработен ред от входния файл.
      Зареждане на данни с MySQL WorkbenchАко съм прав за горното, тогава бих очаквал журнала за зараждането на данни в MySQL Workbench да бъде по-напредничав. На първо място, не се печата информация за номера на реда, така че съобщенията "Data import" (успешен?) и различните възможни грешки са безполезни при определяне на проблемния ред. Трябва да копирам журнала и да индексирам съобщенията във външен текстов редактор, за да определя проблема във файла с данни. След това, бих искал да имам информация само за грешките (напр. някакъв род филтър). Има лента за напредъка, но без каквито и да било цифри - смятам, че съобщение като "Обработване на ред X от NB_LNS_IN_FILE" ще бъде доста полезно, но това би изисквало преброяване на редовете предварително. Също така няма възможност за съхраняване на журнала от зареждането, а копирането му изисква превъртане (т.е. няма възможности като Ctrol+A или Избери всичко).
      Във всеки случай, намирам възможността за зареждане на данни с MySQL Workbench доста полезна, но имайте едно наум ако трябва да зареждате големи обеми от данни (т.е. няколко хиляди или повече реда). В случай, че трябва да зареждате такива обеми от данни е силно препоръчително да прехвърлите файла с данни локално и използвате LOAD DATA INFILE, което според наръчника "чете редове от текстов файл в таблица с много висока скорост".

      2018-06-12

      Време ли е за Slackware 15?

      Последната версия на Slackware (14.2) се появи преди почти 2 години и надгради много пакети, но нещата се движат по-бързо в днешно време, така че просто се чудя не е ли време за нова версия? Аз следя -current, така че виждам някои забележителни промени и надграждания, които се събират там, включително:
      • Основна система:
        • Linux Kernel 4.14 LTS;
        • GNU C Library 2.27;
      • Сървъри:
        • Postfix 3.3 (заменя Sendmail като MTA) и Dovecot 2.3 (заменя imapd като IMAP демон);
        • Apache 2.4.33 (с HTTP/2 поддръжка);
        • ProFTPD 1.3.6 (с mod_sftp и mod_facl поддръжка);
        • Samba 4.6;
        • MariaDB 10.3.7 (много яко като се има в предвид както писах за новите функционалности);
        • Bind 9.11, dhcp 4.3.4, ntp 4.2.8p11 (вече вървящ като ntp:ntp);
      • Разработка:
        • GNU's Compiler Collection 7.3 и LLVM 6.0;
        • Perl 5.26, PHP 7.2, Python 3.6, Ruby 2.5 и Rust 1.26;
        • Git 2.17 и Mercurial 4.5;
      • GUI:
        • X.Org 1.20;
        • KDE 4.14.36 (надявах се на Plasma 5.x въпреки това);
        • SeaMonkey 2.49, Firefox 59.0 и Thunderbird 52.8;
        • GTK+ приложения като Pidgin 2.13, Gimp 2.10, и т.н..
      Има 66 нови пакета общо като сред тях са FFmpeg 3.4, нови библиотеки като opus, lame, libbluray, speex, id3lib, libwebp и различни Python модули (напр. docutils, idna и six), които вече имам на SlackPack. Забелязах също SDL2 библиотеката, която нямам и което е страхотно, защото някои пакети вече имат нужда от нея.
      Като цяло има много нови пакети които очаквах като Postfix, Dovecot, Python 3, MariaDB 10.3, GCC 7.3 и др., които ще направят страхотна нова версия която и когато и да бъде тя. Единственото разочарование за мен е, че KDE още е 4.14 и Qt 4.8, a някои приложения вече се нуждаят от KDE 5 и Qt 5 (напр. като KDESvn, cppcheck's GUI, и др.). Пакета pkgtools вече е 15.0 в -current, така че време ли е за Slackware 15?

      2018-05-30

      Първи опити с надграждане на място от MySQL 5.7 до MySQL 8.0

      Писах преди, че надграждането на място не е възможно от MySQL 8.0.4 към 8.0.11, но то официално се поддържа между GA версите (но не и през MySQL Installer - виж #90619 и по-скоро #79315). Така че днес направих първите си опити за мигриране на моя MySQL 5.7 сървър до MySQL 8.0 чрез копиране на данните и конфигурацията в Slackware виртуална машина. Да започваме...
      • Първи опти:
      2018-05-30T16:42:28.485076Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.11) starting as process 18078
      2018-05-30T16:42:28.727435Z 1 [ERROR] [MY-012526] [InnoDB] InnoDB: Upgrade after a crash is not supported. This redo log was created with MySQL 5.7.22. Please follow the instructions at http://dev.mysql.com/doc/refman/8.0/en/upgrading.html
      2018-05-30T16:42:28.727509Z 1 [ERROR] [MY-012930] [InnoDB] InnoDB: Plugin initialization aborted with error Generic error.
      2018-05-30T16:42:29.228125Z 1 [ERROR] [MY-011013] [Server] Failed to initialize DD Storage Engine.
      2018-05-30T16:42:29.228520Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed.
      2018-05-30T16:42:29.228554Z 0 [ERROR] [MY-010119] [Server] Aborting
      2018-05-30T16:42:29.235976Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.11)  Source distribution.


      Е, наистина си опитах шансовете просто копирайки папката с данни на работещия MySQL 5.7 сървър :-)

      Решение: Да се направи чисто копие на папката с данните при спрян сървър.
      • Втори опит:
      2018-05-30T16:53:06.475573Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.11) starting as process 18236
      2018-05-30T16:53:08.332393Z 0 [Warning] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-001287 - 'validate password plugin' is deprecated and will be removed in a future release. Please use validate_password component instead
      InnoDB MEMCACHED: Memcached uses atomic increment
       InnoDB_Memcached: Unable to open table 'innodb_memcache/containers'
       InnoDB_Memcached: Please create config table'containers' in database 'innodb_memcache' by running 'innodb_memcached_config.sql. error Table not found'
      Failed to initialize instance. Error code: 13
      2018-05-30T16:53:13.256478Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
      2018-05-30T16:53:13.257272Z 0 [ERROR] [MY-010262] [Server] Can't start server: Bind on TCP/IP port: Address already in use
      2018-05-30T16:53:13.257283Z 0 [ERROR] [MY-010257] [Server] Do you already have another mysqld server running on port: 3306 ?

      2018-05-30T16:53:13.257298Z 0 [ERROR] [MY-010119] [Server] Aborting
       InnoDB_Memcached: Memcached plugin is still initializing. Can't shut down it.
      2018-05-30T16:53:29.161133Z 0 [Warning] [MY-011068] [Server] The syntax 'validate password plugin' is deprecated and will be removed in a future release. Please use validate_password component instead.
      2018-05-30T16:53:30.304586Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.11)  Source distribution.


      Разбира се, имам друг MySQL 8.0 сървър слушащ на порт 3306, така че нека оправя конфигурацията.

      Решение: Смяна на port в конфигурационния файл.
      • Трети опит:
      2018-05-30T17:04:57.144549Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.11) starting as process 18571
      2018-05-30T17:04:57.523116Z 0 [Warning] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-001287 - 'validate password plugin' is deprecated and will be removed in a future release. Please use validate_password component instead
      2018-05-30T17:04:57.630947Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
      2018-05-30T17:04:57.633668Z 0 [ERROR] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-001146 - Table 'mysql.component' doesn't exist
      2018-05-30T17:04:57.633699Z 0 [Warning] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-003543 - The mysql.component table is missing or has an incorrect definition.
      2018-05-30T17:04:57.633776Z 0 [ERROR] [MY-011071] [Server] unknown option '--secure-auth'
      2018-05-30T17:04:57.633787Z 0 [Warning] [MY-010952] [Server] The privilege system failed to initialize correctly. If you have upgraded your server, make sure you're executing mysql_upgrade to correct the issue.
      2018-05-30T17:04:57.633840Z 0 [ERROR] [MY-010119] [Server] Aborting
      2018-05-30T17:04:58.636827Z 0 [Warning] [MY-011068] [Server] The syntax 'validate password plugin' is deprecated and will be removed in a future release. Please use validate_password component instead.


      Даа, речника на данните все още не е надграден, но за това ми трябва работещ сървър а има още и грешка за непозната конфигурационна директива.

      Решение: Премахване на secure-auth директивата от конфигурационния файл, защото беше премахната в 8.0.3 (виж още бележките към версията).
      • Четвърти опит:
      2018-05-30T17:06:21.153201Z 0 [ERROR] [MY-011071] [Server] unknown variable 'max_tmp_tables=64'

      Решение: Също като отгоре. Премахване на max_tmp_tables директивата от конфигурационния файл.
      • Пети опит:
      2018-05-30T17:10:36.750614Z 0 [ERROR] [MY-011071] [Server] unknown variable 'query_cache_type=1'

      Дам, забравих, че кеша на заявките е премахнат също...

      Решение: Премахване на query_cache_type и query_cache_size директивите от конфигурационния файл, тъй като Query Cache беше премахнат в MySQL 8.
      • Шести опит:
      2018-05-30T17:11:18.941821Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.11) starting as process 18803
      2018-05-30T17:11:19.333818Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
      2018-05-30T17:11:19.335972Z 0 [ERROR] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-001146 - Table 'mysql.component' doesn't exist
      2018-05-30T17:11:19.336010Z 0 [Warning] [MY-013129] [Server] A message intended for a client cannot be sent there as no client-session is attached. Therefore, we're sending the information to the error-log instead: MY-003543 - The mysql.component table is missing or has an incorrect definition.
      2018-05-30T17:11:19.348988Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.user].
      2018-05-30T17:11:19.349014Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.db].
      2018-05-30T17:11:19.349020Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.tables_priv].
      2018-05-30T17:11:19.349026Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.columns_priv].
      2018-05-30T17:11:19.349031Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.procs_priv].
      2018-05-30T17:11:19.349035Z 0 [Warning] [MY-010929] [Server] Storage engine 'MyISAM' does not support system tables. [mysql.proxies_priv].

      2018-05-30T17:11:19.352944Z 0 [ERROR] [MY-013143] [Server] Column count of mysql.user is wrong. Expected 49, found 45. The table is probably corrupted
      2018-05-30T17:11:19.352980Z 0 [Warning] [MY-010966] [Server] ACL table mysql.role_edges missing. Some operations may fail.
      2018-05-30T17:11:19.352987Z 0 [Warning] [MY-010966] [Server] ACL table mysql.default_roles missing. Some operations may fail.
      2018-05-30T17:11:19.352992Z 0 [Warning] [MY-010966] [Server] ACL table mysql.global_grants missing. Some operations may fail.
      2018-05-30T17:11:19.352997Z 0 [Warning] [MY-010966] [Server] ACL table mysql.password_history missing. Some operations may fail.

      2018-05-30T17:11:19.353420Z 0 [ERROR] [MY-010965] [Server] Missing system table mysql.global_grants; please run mysql_upgrade to create it.
      2018-05-30T17:11:19.365069Z 0 [Warning] [MY-010727] [Server] System table 'func' is expected to be transactional.
      2018-05-30T17:11:19.366847Z 0 [Warning] [MY-010405] [Repl] Info table is not ready to be used. Table 'mysql.slave_master_info' cannot be opened.

      2018-05-30T17:11:19.366874Z 0 [ERROR] [MY-010422] [Repl] Error in checking mysql.slave_master_info repository info type of TABLE.
      2018-05-30T17:11:19.368238Z 0 [ERROR] [MY-010415] [Repl] Error creating master info: Error checking repositories.
      2018-05-30T17:11:19.368273Z 0 [ERROR] [MY-010426] [Repl] Slave: Failed to initialize the master info structure for channel ''; its record may still be present in 'mysql.slave_master_info' table, consider deleting it.

      2018-05-30T17:11:19.368280Z 0 [ERROR] [MY-010529] [Repl] Failed to create or recover replication info repositories.
      2018-05-30T17:11:19.373821Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.11'  socket: '/var/lib/mysql/mysqld57.sock'  port: 3316  Source distribution.


      Успех! Сървъра вече работи, но очевидно има нужда от надгражане, защото има или липсващи системни таблица или такива още на MyISAM. Обаче, не трябва ли това да стане автоматично? Поне оставам с такова впечатления четейки стъпка 8 за In-Place Upgrade в наръчника. Както и да е, стъпка 9 е пускане на mysql_upgrade, така че след пускане на командата грешките в журнала изчезват.

      Разбира се, просто си играех, но поне сега имам конфигурационен файл готов за 8.0 и проверих процедурата за надграждане за моя случай. Обаче, трябва да проверя също съвместимостта на приложенията си, така че истинското надграждане ще стане по-нататък.

      P.S. Готин начин за проверка на проблеми с конфигурацията е описан в How to check MySQL Config files от Петър Зайцев.

      2018-05-28

      MariaDB 10.3 добавя още повече възможности за разработка от MySQL 8.0

      Миналия петък (25-ти Май) MariaDB 10.3.7 беше пусната като стабилна (General Availability). Най-накрая успях да проверя бележките към версията и (не неочаквано) открих някои възможности, които все още ни липсват в MySQL (дори и в пуснатата преди малко повече от месец 8.0.11 GA за която писах). Искам да подчертая следващите забележителни промени свързани с разработка (от което се интересувам най-много):
      • System-versioned tables (също познато като AS OF);
      • Aggregate stored functions (CREATE AGGREGATE FUNCTION и FETCH GROUP NEXT ROW в цикли);
      • FOR loop (FOR ... DO ... END FOR израз и FOR ... LOOP ... END LOOP израз в sql_mode=ORACLE, виж MDEV-10581 и MDEV-12098);
      • Sequences (като алтернатива на AUTO INCREMENT за "повече контрол на това как се създават числата за идентификатори");
      • INTERSECT и EXCEPT операции за множества;
      • ROW тип данни (за променливи представляващи група от полета - т.е. редове или записи - в съхранени програми);
      • TYPE OF и ROW TYPE OF обвързани типове данни (за променливи представляващи колони или редове в съхранени програми);
      • DELETE и UPDATE изрази базирани на подзаявки по същата таблица;
      • Stored packages (с подобни на Oracle CREATE PACKAGE и CREATE PACKAGE BODY изрази в sql_mode=ORACLE).
      Уау. Работили са здраво, това е сигурно. Ще трябва тепърва да пробвам всички тези нови възможности собственоръчно, но съм доста развълнуван да ги видя достъпни в "един от най-популярните сървъри за бази данни". За съжаление, нито една от тези не е достъпна в MySQL. Отдолу е моя списък на това което все още липсва в MySQL (и MariaDB):
      Функционалност MariaDB MySQL Стандарт
      SQL Модифициране на данни в таблица базирано на подзаявка по същата таблица 10.3.2 (2017-11-09) n/a
      EXCEPT или MINUS и INTERSECT оператори за множества 10.3.0 (2017-04-16) n/a SQL:2003
      Времеви заявки (AS OF) 10.3.4 (2018-01-18) n/a SQL:2011
      DDL CHECK ограничения 10.2.1 (2016-07-04) n/a SQL:1999
      Подялба на таблици с външни ключове n/a n/a
      Времеви таблици (WITH SYSTEM VERSIONING) 10.3.4 (2018-01-18) n/a SQL:2011
      CREATE OR REPLACE за таблици, тригери и съхранени програми 10.0.8 (2014-02-10), 10.1.4 (2015-04-13) и 10.1.3 (2015-03-02) n/a
      Разрешаване/забраняване за тригери n/a n/a
      Последователности 10.3.0 (2017-04-16) n/a SQL:2003
      Работещо преименуване на схеми (RENAME {DATABASE | SCHEMA} израз) n/a n/a
      Изгледи Съхраняване на точния израз на изгледа на сървъра n/a n/a n/a
      Напълно обновими изгледи с INSTEAD OF тригери n/a n/a SQL:2008
      Материализирани изгледи n/a n/a
      Съхранени програми Аргументи с подразбираща се стойност n/a n/a
      FOR цикъл 10.3.3 (2017-12-23) n/a
      Анонимни блокове код (или съставни изрази извън програми) 10.1.1 (2014-10-17) n/a
      Записи, типове данни свързани с колона или ред 10.3.0 (2017-04-16) n/a
      Съхранени модули или пакети 10.3.5 (2018-02-26) n/a
      Тригери на ниво израз или схема n/a n/a
      Съоръжения за дебъгване n/a n/a n/a
      Външни програми на JavaScript, Perl, PHP, и т.н. n/a n/a

      Съвсем ясно е от горната таблица, че MySQL има повече сиви петна от MariaDB. Добавил съм също и съответния SQL стандарт където е приложимо, така че в тази връзка MariaDB има по-широка поддръжка на стандарта. Изглежда ми, че в последната стабилна версия на MariaDB са реализирани повече "подобни на Oracle" възможности, отколкото в MySQL който се разработва от Oracle.
      Така че, заслужава ли си да се сменя базата? Вярвам, че ще продължа да ползвам както MySQL така и MariaDB (която е база по подразбиране във всички Linux дистрибуции) и причината за това е, че двете бази стават все по-различни с времето. Има възможности за разработка в MySQL (напр. JSON типа данни, Склада за документи), които не съществуват в MariaDB и обратното. Все още съм доста свикнал с ползването на MySQL Workbench за ежедневна работа с MySQL бази данни, но поддръжката за MariaDB в него чезне и освен ако MySQL не добави същите възможности, се съмнявам, че новите функционалности за разработка ще бъдат използваеми в Workbench, което засяга работата и производителността ми.