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

2019-01-31

Моите MySQL бъгове

Откакто започнах да използвам MySQL 3.23.x пред годините ми в университета се опитвах да решавам проблемите си сам както с другия свободен софтуер и софтуер с отворен код, който използвах. Първоначално беше повече обучение (или липса на знание ако щете), но след това проблемите ставаха по-сложни и трудни за решаване. Е, успявах повечето пъти, така че не вземах в предвид докладване на бъгове или търсене на поддръжка. Обаче еко системата на  MySQL порасна от тогава, софтуера стана по-сложен и базата с изходен код се увеличи значително, така че днес е наивно да се смята, че човек може да оправи всички проблеми, които среща без да се задълбава в вътрешните елементи на продукта или разчита на професионална поддръжка. Първото е възможно само за MySQL разработчици добре запознати с базата с код и големи организации като Facebook, Booking, и т.н., които имат специализирани екипи и редовно допринасят кръпки. Второто зависи от вас и разбира се компанията предоставяща поддръжка.

Не съм докладвал много бъгове за MySQL - само 21, но вече смятам да докладвам всичко което открия, което изглежда като бъг, защото това е правилното нещо. Може и да се справя с проблема сам, но някой може да се натъкне на същото и трябва поне да е наясно, че това е познат (и евентуално вече решен) проблем. С всеки един от тези научих по нещо малко, така че тук отдолу правя преглед на бъговете си до сега описвайки тяхната съдба в хронологичен ред.
  1. Бъг 20098 (първият ми) беше докладван на 2006-05-26 и е със състояние "No Feedback" от 2006-07-01. Беше за Query browser търсещ файл, който не съществува (preferences.glade). Бях забравил за този и открих, че е затворен по-късно, защото не съм предоставил обратна връзка, което е забавно, защото бях предоставил поисканата информация...
  2. Бъг 69459 беше докладван на 2013-06-13 и е в състояние "Can't repeat" от 2013-12-24. Беше за MySQL Workbench сриващ се при въвеждане на точка в SQL низ когато е разрешено автоматично довършване на кода. Докладвах бъга за версия 5.2.47 CE, но бях посъветван да пробвам 6.0.7, която работеше, така че бъга не получи повече внимание тъй като 5.2 серията не получи повече обновления.
  3. Бъг 73076 (първият ми потвърден и оправен) беше докладван на 2014-06-22 и е със състояние "Closed" от 2014-08-26. Беше за MySQL Workbench всъщност записваш промените в набор с редове когато само са приложени. Беше гаден бъг правещ ежедневната ми работа с Workbench трудна, тъй като трябваше да внимавам да не приложа (извинявам се запиша) твърде рано. Проблема се появи в 6.0.x, 6.1.x и беше оправен в крайна сметка с пускането на 6.2.2 на 2014-09-05 (виж бележки към версия) след като беше потвърден от поддръжката.
  4. Бъг 73079 беше докладван на 2014-06-23 и е в състояние "Closed" от 2014-09-15. Беше за MySQL Workbench, който не опресняваше клетката след задаване на стойността на NULL. Засягаше 6.1.x и ранните 6.2.x версии. Въпреки, че не беше официално потвърдено, за мен това беше регресия, но по-важното е, че беше оправен с пускането на 6.2.3 на 2014-09-23 (виж бележки към версия).
  5. Бъг 73708 беше докладван на 2014-08-25 и е със състояние "Closed" от 2014-12-01. Беше за MySQL Workbench моделите, които бяха напълно разбъркани. Забравих този за няколко месеца и предоставих поисканата обратна връзка после, за да разбера, че проблема е вече оправен с пускането на  6.2.4 на 2014-11-20, въпреки че нищо не беше споменато в бележките към версия.
  6. Бъг 73770 (най-стария ми все още отворен) беше докладван на 2014-08-29 и все още е в състояние "Verified" от 2018-02-05. Представлява заявка за нова функционалност в MySQL синхронизатора между модел и база с данни да показва действителните разлики. Който е ползвал тази възможност би трябвало да знае, че прилагането на промените от модел в базата с данни може да бъде доста досадно, защото винаги има някакви неочаквани промени и още повече такива, които не можеш да разбереш. Виждаш само скрипта за обновяване, но ще бъде хубаво да се виждат действителните разлики, което в някои случаи може въобще да не са разлики (виж 90772 по-долу).
  7. Бъг 82202 беше докладван на 2016-07-12 и е със състояние "Closed" от 2018-01-31. Беше за невъзможност за свързване на Connector/ODBC 5.3.6 към споделената библиотека libmysqlclient.so заради неопределени символи (напр. my_malloc, my_free, и т.н.). Проблема беше бързо обяснен, но след това затворен с "Not A Bug". Беше отворен отново след като Fedora отговорник докладва същия проблем и в крайна сметка оправен с пускането на Connector/ODBC 5.3.10 на 2018-01-30 (виж бележки към версия).
  8. Бъг 84951 (първата ми предложена кръпка) беше докладван на 2017-02-10 и е със състояние "Duplicate" от 2017-02-12. Беше за проблем с изграждането на MySQL Workbench 6.3.9, заради компилационни грешки в jsonparser.cpp и jsonview.cpp, за които предложих кръпка. Бъга беше направен двойник на 84886, който също съдържаше кръпка предоставена два дена по-рано, но беше затворен на 2018-05-14 като "Won't fix", защото те "вече не поддържат 32 битови системи" (!?).
  9. Бъг 89608 беше докладван на 2018-02-09 и е все още в състояние "Verified" от 2018-02-13. Това е заявка за нова функционалност за това съобщенията за изискванията към паролите в MySQL Workbench да отговарят на конфигурацията на сървъра, така че да са по-полезни. Предоставих примерен код за това как може да бъде направено и дори написах SQL функция за да пробвам идеята.
  10. Бъг 89615 беше докладван на 2018-02-10 и е със състояние "Unsupported" от 2018-08-23. Беше за неуспех с изграждането на MySQL Shell 1.0.10, заради пропадаща компилация за неопределени vio* функции. Беше свързан с 82202 и въпреки че беше потвърден по-късно беше затворен с обяснението, че "MySQL Shell 1.0 вече не се поддържа и трябва да се ползва 8.0 вместо това" (!?) на което реагирах малко грубо, но наистина не разбирам такива отговори.
  11. Бъг 90619 беше докладван на 2018-04-25 и е със състояние "Duplicate" на 79315 от 2018-04-25. Беше за това, че MySQL Installer не предлага надграждане от MySQL 5.7 до 8.0, което беше обяснено като "не е бъг", защото "работи според очакванията", така че явно MySQL Installer не поддържа надграждания между главни версии. Надявам се това да се промени в бъдеще.
  12. Бъг 90620 (първият ми от серия) беше докладван на 2018-04-25 и е все още в състояние "Verified" от 2018-04-26. Този е за MySQL Workbench 8.0.11's SQL редактора, който показва грешка на SELECT заявка с прозоречни функции. Не бихте очаквали MySQL Workbench имащ същата версия като сървъра да не поддържа новите възможности на сървъра, но повече за това по-късно.
  13. Бъг 90727 беше докладван на 2018-05-03 и е със състояние "Closed" от 2018-06-01. Беше за невъзможност да се свърже Connector/C++ 1.1.11 поради липсващи mysql_sys и mysql_strings библиотеки. Оказа се регресия от някакви специфични за Solaris промени, които не са направени Solaris специфични. Свързах се с разработчика и беше обявено за оправено в 1.1.12, която излезе на 2019-01-28 (виж бележки към версия), така че за 1.1.11 трябваше да закърпя сам.
  14. Бъг 90772 беше докладван на 2018-05-06 (St George's Day) и е все още в състояние "Verified" от 2018-05-09. Беше за MySQL Workbench синхронизатора правещ разлика между варианти за избягване на единични кавички (напр. израза COMMENT 'Currency\' symbol' е различен от израза COMMENT 'Currency''s symbol'). Това е защото MySQL Workbench позволява избягване с наклонена черта и сървъра го приема за изпълнение, но след това го пренаписва като избягване с единична кавичка. Така, при следващата синхронизация разликата остава (т.е. все едно не сте синхронизирали въобще).
  15. Бъг 90876 беше докладван на 2018-05-15 и е със състояние "Closed" от 2018-06-21. Беше за MySQL Shell 8.0.11 даващ грешка 5115 при добавяне на документи към колекция в 5.7 сървър, но това за което беше всъщност е автоматично създавани идентификатори както обясних в подробности в статията ми MySQL Shell и автоматичното създаване на идентификтори за документи. Този предизвика обновяване на документацията и тъй като никой друг нямаше този проблем предполагам, че е добре, но за мен такива проблеми чупят обратната съместимост.
  16. Бъг 91841 беше докладван на 2018-07-31 и е със състояние "Closed" от 2019-01-25. Беше а невъзможност да се изгради MySQL Connector/ODBC 5.3.11, заради компилационни грешки. Успях да оправя компилационните грешки сам (виж кръпка) докато чаках за помощ и обяснение. А обяснението беше, че е двойник на вътрешен бъг, "който обяснява причините за неуспеха", но който не мога да прочета. Забавното нещо в това беше, че имаше повече от 400 реда изтрити от началото на заглавен файл най-вероятно свързано с обновявания на текста с авторското право. Беше оправен с пускането на 5.3.12 на 2019-01-28 (виж бележки към версия).
  17. Бъг 92898 беше докладван на 2018-10-23 и е със състояние "Not a Bug" от 2018-10-23. Смятам този за единствената ми "заявка за поддръжка" и бях доволен, че беше обяснен същия ден.  Беше за това, че ударих несъвместима промяна при надграждане от 8.0.12 до 8.0.13, защото все още имах някои стари изгледи използващи ASC или DESC квалификатори с GROUP BY клауза. В тази връзка искам да благодаря на MySQL подробните бележки към версия, които публикуват, защото в този случай дори да ги четеш внимателно можеш да изпуснеш нещо смятайки, че не те засяга. Поради тази причина е силно препоръчително да се ползва Upgrade Checker Utility на MySQL Shell, който може да ви кажеш за грешки със съвместимостта и проблеми предварително.
  18. Бъг 92900 беше докладван на 2018-10-23 и е в състояние "Verified" от 2018-10-23. Този е за това, че в MySQL Workbench 8.0.13 липсва поддръжка за изрази в DEFAULT, въпреки че функционалността се поддържа от същата версия на сървъра.
  19. Бъг 92908 беше докладван на 2018-10-23 и е в състояние "Verified" от 2018-10-23. Този е за това, че в MySQL Workbench 8.0.13 липсва поддръжка за изрази като части от ключ, въпреки че функционалността се поддържа от същата версия на сървъра.
  20. Бъг 93835 беше докладван на 2019-01-07 и е в състояние "Verified" от 2019-01-10. Това е заявка за нова функционалност за това MySQL Workbench да показва предупреждение при използване на ключова дума като идентификатор (напр. имена на таблици и колони). Отворих го след като Frédéric Descamps предложи това в менение изразено в LinkedIn. Стискам палци да бъде направено.
  21. Бъг 94012 беше докладван на 2019-01-23 и е в състояние "Verified" от 2019-01-23. Този е за това, че MySQL Workbench 8.0.14 не разпознава новата ключова дума LATERAL и дава грешка след нея в SQL редактора. За сега това е последния от серията ми за това, че MySQL Workbench не поддържа възможностите на сървъра, въпреки че са със същата версия. Бъга беше номиниран като MySQL Бъг на деня от Valerii Kravchuk на същия ден.

Надявам се не съм ви отегчил с цялата тази информация отгоре. Не винаги е лесно правилно да се обясни един проблем, но аз имам дост опит бидейки от "другата страна", така че смятам, че знам каква информация е необходима, за да може един проблем да бъде изследван старателно. Все пак докладването на бъгове вероятно е изкуство и очаквам представянето на Valerii Kravchuk на тема How to create a useful MySQL bug report на FOSDEM в Събота.

Някои от бъговете ми са чисто технически (напр. 82202, 84951, 89615, 90727 и 91841) за които съм докладвал всички подробности и все пак обясненията на някои от тях ми изглеждат твърде странни (напр. все не се поддържат 32 битови системи, MySQL Shell 1.0 вече не се поддържа и версия 8.0 трябва да се използва вместо това), въпреки че проблема и това което трябва да се оправи стана доста ясно. Не разбирам как може да не се пуска нова поддържаща версия, когато има отворени бъгове за последната такава версия от серията? Това което производителите трябва да разберат е, че като отговорник за пакети за мен е по-сложно да поддържам кръпки за проблеми, които не се оправят в продукта.

Направих серия от бъгове за неподдържани възможности в MySQL Workbench (напр. 90620, 92900, 92908 и 94012), което ме накара да се замисля за значението на уеднаквяването на номерата на версиите, което беше направено с пускането на MySQL 8.0.11 като общодостъпна версия (виж MySQL 8.0: It Goes to 11!). Както разбирам публикацията, това беше направено, за да ползваме "правилната версия" на всички продукти. Това като цяло е добра идея, но не трябва ли "правилната версия" да поддържа същия набор от възможности като сървъра? Предполага се, че потребителите ще бъдат по-малко объркани ако е така, но за сега определено това не е случая с Workbench. Надявам се ситуацията да се подобри в бъдеще.

Искам да завърша тази статия с няколко завършващи мисли. Като разработчик съм наясно, че никога не може да има софтуер без никакви бъгове. Обаче, като потребител очаквам, когато бъг е правилно докладван и проблема е ясен решението да не трябва да отнема толкова много време, но разбира се това което наистина има значение са приоритетите, а те обикновено са толкова по-високи колкото броя на засегнатите потребители е по-голям.

2019-01-23

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

С пускането на MySQL 8.0.14 Oracle запазва вече установената практика да въвежда нови възможности за разработчици дори с версии за поддръжка, които обикновено съдържат само малки подобрения и най-вече поправки на бъгове. Разгледах бележките към версията на 8.0.14, публикацията The MySQL 8.0.14 Maintenance Release is Generally Available на и разбира се наръчника, експериментирах и тук отдолу е моя избор на нови възможности свързани с разработка.

Латерални производни таблици (Lateral derived tables)

Преди MySQL 8.0.14 не беше възможно за производни таблици да се обръщат към (зависят от) колони на предходните таблици в FROM клаузата. Сега това ограничение е премахнато с добавянето на ключова дума LATERAL (виж Lateral derived tables). Ключовата дума LATERAL означава, че производната таблица зависи от предходната таблица от ляво. Можете да имате повече от една LATERAL производна таблица в заявка и всяка ще зависи само от предходната таблица или производна таблица. Латералните производни таблици са така наречения "for each" цикъл на SQL и това прави възможни някои операции, които иначе не са възможни или са по-малко ефикасни.
Ето един пример. Да кажем, че искате да изчислите минималната, средната и максималната заплата за всеки отдел в организацията. Преди трябваше да го напишете така:
План за изпълнение на заявката с производна таблица

SELECT D.dname, DT.min_sal, DT.avg_sal, DT.max_sal
  FROM dept D

       LEFT JOIN
       (SELECT E.deptno, MIN(E.sal) min_sal, AVG(E.sal) avg_sal, MAX(E.sal) max_sal
          FROM emp E
         GROUP BY E.deptno
       ) AS DT
       ON DT.deptno = D.deptno;


И така да използвате производна таблица DT, за да изчислите мин/сред/макс заплата за всички отдели от таблицата emp и тогава съедините с таблица dept получавайки следния резултат:

+------------+---------+-------------+---------+
| dname      | min_sal | avg_sal     | max_sal |
+------------+---------+-------------+---------+
| ACCOUNTING | 1300.00 | 2916.666667 | 5000.00 |
| RESEARCH   |  800.00 | 2175.000000 | 3000.00 |
| SALES      |  950.00 | 1566.666667 | 2850.00 |

| OPERATIONS |         |             |         |
+------------+---------+-------------+---------+
4 rows in set (0.0014 sec)


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

SELECT D.dname,
       (SELECT MIN(E.sal) FROM emp E WHERE E.deptno = D.deptno) AS min_sal,
       (SELECT AVG(E.sal) FROM emp E WHERE E.deptno = D.deptno) AS avg_sal,
       (SELECT MAX(E.sal) FROM emp E WHERE E.deptno = D.deptno) AS max_sal
  FROM dept D;


което няма да бъде ефикасно (представете си таблица с продажби и хиляди търговци ако искате да оцените техните продажби), защото три заявки ще трябва да вършат работата на една. Не е възможно да се ползва само една подзаявка за изчисляване на всички необходими стойности в SELECT, защото такива подзаявки трябва да са скаларни. Подобна заявка ще предизвика грешка Error Code: 1241. Operand should contain 1 column(s) ако пробвате.
Ако се опитате да свържете производната таблица към другата таблица с заявка като следната:

SELECT D.dname, DT.min_sal, DT.avg_sal, DT.max_sal
  FROM dept D,
       (SELECT MIN(E.sal) min_sal, AVG(E.sal) avg_sal, MAX(E.sal) max_sal
          FROM emp E
         WHERE E.deptno = D.deptno
       ) AS DT;


ще получите грешка Error Code: 1054. Unknown column 'D.deptno' in 'where clause', защото таблица D не е позната на производната таблица. Заявката е незаконна в SQL-92, но в SQL-1999 става законна ако производната таблица се предшества от ключовата дума LATERAL:

SELECT D.dname, LDT.min_sal, LDT.avg_sal, LDT.max_sal
  FROM dept D,
       LATERAL
       (SELECT MIN(E.sal) min_sal, AVG(E.sal) avg_sal, MAX(E.sal) max_sal
          FROM emp E
         WHERE E.deptno = D.deptno
       ) AS LDT;

План за изпълнение на заявката с латерална производна таблица

и създава следния резултат:

+------------+---------+-------------+---------+
| dname      | min_sal | avg_sal     | max_sal |
+------------+---------+-------------+---------+
| ACCOUNTING | 1300.00 | 2916.666667 | 5000.00 |
| RESEARCH   |  800.00 | 2175.000000 | 3000.00 |
| SALES      |  950.00 | 1566.666667 | 2850.00 |
| OPERATIONS |    NULL |        NULL |    NULL |
+------------+---------+-------------+---------+
4 rows in set (0.1182 sec)


Както се вижда от графиката на плана за изпълнение отдясно в този случай няма групиране, но MySQL дава по-висока цена, защото достъпа до производната таблица е чрез пълно сканиране на таблица. По-интересната информация обаче е в табличния план за изпълнение (колона partitions е преднамерено скрита):

+----+-------------------+------------++------+---------------+-----------+---------+-------------------+------+----------+----------------------------+
| id | select_type       | table      || type | possible_keys | key       | key_len | ref               | rows | filtered | Extra                      |
+----+-------------------+------------++------+---------------+-----------+---------+-------------------+------+----------+----------------------------+
|  1 | PRIMARY           | D          || ALL  | NULL          | NULL      | NULL    | NULL              |    4 |      100 | Rematerialize (<derived2>) |
|  1 | PRIMARY           | <derived2> || ALL  | NULL          | NULL      | NULL    | NULL              |    2 |      100 | NULL                       |
|  2 | DEPENDENT DERIVED | E          || ref  | fk_deptno     | fk_deptno | 5       | dept_emp.D.deptno |    4 |      100 | NULL                       |
+----+-------------------+------------++------+---------------+-----------+---------+-------------------+------+----------+----------------------------+
3 rows in set, 2 warnings (0.0010 sec)
Note (code 1276): Field or reference 'dept_emp.D.deptno' of SELECT #2 was resolved in SELECT #1
Note (code 1003): /* select#1 */ select `dept_emp`.`d`.`dname` AS `dname`,`ldt`.`min_sal` AS `min_sal`,`ldt`.`avg_sal` AS `avg_sal`,`ldt`.`max_sal` AS `max_sal` from `dept_emp`.`dept` `d` join lateral (/* select#2 */ select min(`dept_emp`.`e`.`sal`) AS `min_sal`,avg(`dept_emp`.`e`.`sal`) AS `avg_sal`,max(`dept_emp`.`e`.`sal`) AS `max_sal` from `dept_emp`.`emp` `e` where (`dept_emp`.`e`.`deptno` = `dept_emp`.`d`.`deptno`)) `ldt`

Има две нови информация и допълнителна бележка. Плана ясно показва, че производната таблица E (derived2) е зависима (DEPENDENT) от другата таблица и че тя се материализира отново за всеки ред от D (виж EXPLAIN extra information). Това е причината поради която латералните производни таблици са познати също като "for each" цикъла на SQL. Бележката дава информация за това как външното позоваване в производната таблица е разрешено.

Разбира се MySQL Workbench (дори надграден до 8.0.14 също) отново не е запознат с новия синтаксис (виж предишната ми публикация Нови възможности за разработчици в MySQL 8.0.13), защото не оцветява правилно новата ключова дума и показва грешка в SQL редактора точно след нея. Докладвах това като бъг 94012, но нямам много надежда, тъй като 90620, 92900 и 92908 бяха потвърдени, но са все още отворени. Номерата на версиите нямат голямо значение в днешни дни :-)

Моля, обърнете внимание, че е възможно да се направи връзка с външната таблица ако производната таблица е в подзаявка (виж пример в WL#461).

Агрегатни JSON функции вече може да се ползват като прозоречни функции

Вече е възможно да се ползват агрегатни функции JSON_ARRAYAGG и JSON_OBJECTAGG като прозоречни функции с използването на OVER клауза (виж Window Function Concepts and Syntax). Това прави всички (освен COUNT(DISTINCT) и GROUP_CONCAT) от агрегатните функции възможни за употреба като прозоречни функции след като побитовите AND/OR/XOR функции бяха направени такива с MySQL 8.0.12. Ето един пример:

SELECT E.ename, E.sal,
       AVG(E.sal) OVER dw AS avg_sal,
       JSON_OBJECTAGG(D.dname, E.sal) OVER dw AS dept_sal
  FROM emp  E,
       dept D
 WHERE E.deptno = D.deptno
WINDOW dw AS (PARTITION BY D.deptno);


+--------+---------+-------------+------------------------+
| ename  | sal     | avg_sal     | dept_sal               |
+--------+---------+-------------+------------------------+
| CLARK  | 2450.00 | 2916.666667 | {"ACCOUNTING": 1300.0} |
| KING   | 5000.00 | 2916.666667 | {"ACCOUNTING": 1300.0} |
| MILLER | 1300.00 | 2916.666667 | {"ACCOUNTING": 1300.0} |
| SMITH  |  800.00 | 2175.000000 | {"RESEARCH": 3000.0}   |
| JONES  | 2975.00 | 2175.000000 | {"RESEARCH": 3000.0}   |
| SCOTT  | 3000.00 | 2175.000000 | {"RESEARCH": 3000.0}   |
| ADAMS  | 1100.00 | 2175.000000 | {"RESEARCH": 3000.0}   |
| FORD   | 3000.00 | 2175.000000 | {"RESEARCH": 3000.0}   |
| ALLEN  | 1600.00 | 1566.666667 | {"SALES": 950.0}       |
| WARD   | 1250.00 | 1566.666667 | {"SALES": 950.0}       |
| MARTIN | 1250.00 | 1566.666667 | {"SALES": 950.0}       |
| BLAKE  | 2850.00 | 1566.666667 | {"SALES": 950.0}       |
| TURNER | 1500.00 | 1566.666667 | {"SALES": 950.0}       |
| JAMES  |  950.00 | 1566.666667 | {"SALES": 950.0}       |
+--------+---------+-------------+------------------------+
14 rows in set (0.0021 sec)


Важно е да се отбележи, че MySQL не разрешава повторение на ключове в JSON типа данни, така че в прозорец без подредба функцията JSON_OBJECTAGG ще върне последната стойност за ключа, което може да е неопределено.

Подобрения по X протокол

Според бележките към версията данните вече винаги се обръщат в символния набор utf8mb4 (с използване на utf8mb4_general_ci колация). Другото забележително подобрение е поддръжката на функционалност за подготвяне на заявки. Бележките към версията не предоставят препратка към тази нова функционалност, но е споменал WL#9270 в своята статия, така че вярвам става въпрос за подготвяне на CRUD операции (виж Preparing CRUD Statements). Един прост пример на JavaScript ще бъде следното:

MySQL Shell 8.0.14
Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
Other names may be trademarks of their respective owners.
 MySQL  JS > \connect user@localhost
Creating a session to 'user@localhost'
Your MySQL connection id is 22 (X protocol)
Server version: 8.0.14 MySQL Community Server - GPL
 MySQL  localhost:33060+ ssl  JS > \use test
Default schema `test` accessible through db.
 MySQL  localhost:33060+ ssl  test  JS > var usr = db.createCollection('users')
 MySQL  localhost:33060+ ssl  test  JS > usr.add({name:"User1",age:15})
Query OK, 1 item affected (0.0108 sec)
 MySQL  localhost:33060+ ssl  test  JS > usr.add({name:"User2",age:17})
Query OK, 1 item affected (0.0138 sec)
 MySQL  localhost:33060+ ssl  test  JS > usr.add({name:"User3",age:20})
Query OK, 1 item affected (0.0105 sec)
 MySQL  localhost:33060+ ssl  test  JS > usr.add({name:"User4",age:19})
Query OK, 1 item affected (0.0137 sec)
 MySQL  localhost:33060+ ssl  test  JS > usr.add({name:"User5",age:16})
Query OK, 1 item affected (0.0118 sec)
 MySQL  localhost:33060+ ssl  test  JS > usr.find()
[
    {"_id": "00005c46e7e5000000000000000a","age": 15,"name": "User1"},
    {"_id": "00005c46e7e5000000000000000e","age": 17,"name": "User2"},
    {"_id": "00005c46e7e5000000000000000f","age": 20,"name": "User3"},
    {"_id": "00005c46e7e50000000000000010","age": 19,"name": "User4"},
    {"_id": "00005c46e7e50000000000000011","age": 16,"name": "User5"}
]
5 documents in set (0.0006 sec)
 MySQL  localhost:33060+ ssl  test  JS > var fcmd = usr.find('age >= :page')
 MySQL  localhost:33060+ ssl  test  JS > fcmd.bind('page', 18)
[
    {"_id": "00005c46e7e5000000000000000f","age": 20,"name": "User3"},
    {"_id": "00005c46e7e50000000000000010","age": 19,"name": "User4"}
]
2 documents in set (0.0006 sec)
 MySQL  localhost:33060+ ssl  test  JS > fcmd.bind('page', 16)
[
    {"_id": "00005c46e7e5000000000000000e","age": 17,"name": "User2"},
    {"_id": "00005c46e7e5000000000000000f","age": 20,"name": "User3"},
    {"_id": "00005c46e7e50000000000000010","age": 19,"name": "User4"},
    {"_id": "00005c46e7e50000000000000011","age": 16,"name": "User5"}
]
4 documents in set (0.0003 sec)

 MySQL  localhost:33060+ ssl  test  JS > fcmd.bind('page', 17)
[
    {"_id": "00005c46e7e5000000000000000e","age": 17,"name": "User2"},
    {"_id": "00005c46e7e5000000000000000f","age": 20,"name": "User3"},
    {"_id": "00005c46e7e50000000000000010","age": 19,"name": "User4"}
]
3 documents in set (0.0004 sec)


римера създава колекция от потребители с техните имена и възраст, после печата цялата колекция. Интересната част започва с реда подчертан в жълто. Той подготвя израз използвайки именуван параметър (анонимни параметри с ? не се поддържат от X протокола), но не го изпълнява. Изпълнението се случва след като се свърже стойност към параметъра и това може да се прави много пъти произвеждайки различни резултати. Интересно е, че в общия журнал първото свързване всъщност изпълнява заявка, след това има подготовка и след това има изпълнения:

Query    SELECT doc FROM `test`.`users` -> usr.find()
Query    SELECT doc FROM `test`.`users` WHERE (JSON_EXTRACT(doc,'$.age') >= 18) -> fcmd.bind('page', 18)
Prepare    SELECT doc FROM `test`.`users` WHERE (JSON_EXTRACT(doc,'$.age') >= ?)
Execute    SELECT doc FROM `test`.`users` WHERE (JSON_EXTRACT(doc,'$.age') >= 16) -> fcmd.bind('page', 16)
Execute    SELECT doc FROM `test`.`users` WHERE (JSON_EXTRACT(doc,'$.age') >= 17) -> fcmd.bind('page', 17)


Използването на подготвени изразни за многократно изпълнявани изрази може да доведе до подобрения в производителността заради спестеното време за синтактичен разбор на заявката, затова това е нещо което трябва да имате в предвид ако трябва да подобрите производителността на приложенията и скриптовете си.

Подобрения в работа с пространствени данни

Функцията ST_Distance вече приема като незадължителен трети параметър мерната единица за връщаната стойност. Възможните стойности са определени в таблица INFORMATION_SCHEMA.ST_UNITS_OF_MEASURE заедно с коефициент за превръщане към основната единица метър (metre), което е и стойността по подразбиране. Ето един пример за изчисляване на разстоянието между София и Сидни в километри и морски мили в SRID 4326:

SELECT ST_Distance(ST_PointFromText('POINT( 42.69751 23.32415)', 4326),
                   ST_PointFromText('POINT(-33.86667 151.20000)', 4326)) / 1000 dist_km;
+--------------------+
| dist_km            |
+--------------------+
| 15431.933058990671 |
+--------------------+
1 row in set (0.0023 sec)


SELECT ST_Distance(ST_PointFromText('POINT( 42.69751 23.32415)', 4326),
                   ST_PointFromText('POINT(-33.86667 151.20000)', 4326), 'nautical mile') dist_nm;


+------------------+
| dist_nm          |
+------------------+
| 8332.57724567531 |
+------------------+
1 row in set (0.0008 sec)

Това завършва моя преглед. Има разбира се много повече в MySQL 8.0.14 не само за разработчици, така че ви насърчавам да изследвате и откриете повече. Препратките в началото на тази статия са добри като начало.

2019-01-15

Трябва ли Slackware да въведе systemd?

Две скорошни събития ме накараха да напиша тази публикация. Първото беше потребител в групата LinuxSlackware във Facebook, който благодареше на Patrick, че не е преминал към systemd. Второто беше скорошен случай където нощната работа на едно приложение пускаше твърде много тежки процеси на един MySQL 8 сървър под RHEL 7, което доведе до изчерпване на паметта и неотговаряща услуга. Във втория случай systemd действа да убие mysqld процеса и да го пусне отново, така че услугата беше възстановена и приложението поне можеше да продължи да работи.

Сега, първото събитие е просто израз на мнение на потребител, което аз, като дългогодишен потребител на Slackware, мога да разбера, защото става въпрос за нещо, с което сме свикнали. То е просто и работи поне за повечето неща.

Обаче, второто събитие ме накара да се замисля, че под Slackware това нямаше да се случи, освен ако не си го направите сами някак си. Въпросът е дали си заслужава, когато вече е направено и работи добре на всички други Линукси, които използвам?

2019-01-10

Нещата които научих за себе си през 2018

За мен 2018-та беше година на надежди, някои от които не се осъществиха. Надявах се на някои промени, но в крайна сметка те не се случиха, в което разбира се няма нищо трагично, тъй като успях да науча някои неща за себе си. В тази статия поглеждам назад към това, което научих за себе си през изминалата година.

Нямам достатъчно опит с отворен код

Това ми беше казано някъде в началото на Март и въобще не възразявам. Допринесъл съм малки кръпки, преводи и буболечки към различни проекти с отворен код в изминалите около 20 години, публикувал съм някои от личните си проекти под отворени лицензи, но ми се иска да бях направил повече. Вярно е, че можех да допринеса повече, но за съжаление просто не намерих времето за това. Все още силно вярвам в софтуера със свободен и отворен код (FOSS), който използвам от университетските ми години, все още използвам и ще продължавам да използвам и за напред. Обаче, в днешни дни не съм толкова придирчив за това, че FOSS трябва също така да е безплатен като в "безплатна бира", което ме приближава към философията на GNU.

Не чета достатъчно/вашите книги

Беше ми предложено от някои да чета повече книги. Да, вероятно мога да чета повече, но все пак чета. И може да не чета същото като вас и вие не сте тези, които ще ми кажете какво да чета както и аз не казвам на вас. Освен книги чета също и някои списания както съм го правил от тийнейджърските си години. И някои неща в мрежата. С тази публикация искам да благодаря на семейството си и приятелите, които ми подариха книги миналата година, така че сега имам към 10 книги в списъка си за 2019. Съжалявам, списъка е лична информация ;-)

Нямам достатъчно опит с тази или онази технология

Научих това през лятото. Все още се смятам за любопитен човек относно технологията, но просто няма как да имам опит с всичко там и не вярвам, че някой може. За мен е по-интересно как човек възприема технологиите и как се справя с промените. Преди две десетилетия софтуера беше доста различен както и инструментите и технологиите, с които се правеше. Темпото на промените се увеличи както и хората заети в разработката на софтуер. Има много хора започнали да разработват софтуер преди едно, две, три десетилетия и повече, които лесно се приспособяват към нови инструменти и технологии, защото имат основни разбирания за това как се прави и работи софтуера. И което е по-важно те знаят, че трябва да учат постоянно и да се включат. Това означава да четат наръчниците, да следят и се възползват от промените, да обсъждат, да докладват буболечки, да правят предложения за нови функционалности, да допринасят колкото им е възможно и като цяло да се включат в общността.

Не съм гъвкав

Това е нещо което ми беше казано преди Коледните празници. Да, вероятно, не съм толкова гъвкав все пак. Запознат съм и разбирам ценностите и принципите на гъвкавата методология, но в същото време не ги споделям напълно.
  • Съгласен съм, че хората и взаимодействията се по-важни от процесите и инструментите, но само второто може да направи първото лесно и ефективно. Без ясни процеси и правилните инструменти дори най-добрите ще се провалят да взаимодействат по начин, който облагодетелства разработката на софтуер. Вярвам, че такива хора първо ще създадат необходимите процеси и инструменти.
  • Съгласен съм, че работещия софтуер е по-важен от подробната документация, но съм виждал софтуер написан с оскъдна или въобще никаква документация. След известно време (напр. 5, 10, 15 години) когато такъв софтуер спре да работи, трябва да бъде надграден или да бъде обяснен на клиент, той първо трябва да мине през процес на обратно инженерство, тъй като най-вероятно първоначалните разработчици са напуснали отдавна компанията. Затова в краткосрочен план и за малки проекти напълно поддържам това, но в дългосрочен план и за големи проекти не мисля, че помага на някого. Проблемът е, че ако не се напише навреме документацията най-вероятно никога няма да бъде написана.
  • Съгласен съм, че сътрудничеството с клиента е по-важно от прегорите по договора, но не всички клиенти могат да сътрудничат ефективно. Някои клиенти дори не знаят какво точно искат, не четат документи (и дори отказват да го правят когато са помолени) съответно не познават софтуера, който ползват и не прехвърлят правилно знанието през времето. Това са само моите скромни наблюдения, но вярвам, че сътрудничеството с клиента трябва да бъде отворено в смисъл, че трябва да бъде достъпно до всички заинтересовани страни сега и в бъдеще. Виждал съм случаи, в които софтуера е разработен в "тясно сътрудничество" между разработчик и човек от страна на клиента чрез лични съобщения, за който след това никой не знае нищо и не иска да знае.
  • Съгласен съм, че реакцията на промените е по-важно от следването на план, но реакцията на постоянни промени означава, че няма план и обхват на проекта въобще. Проектите, които започват като мехурче и постоянно се променят лесно се деформират и излизат извън контрол. Такива проекти обикновено се провалят. Виждал съм някои никога не свършващи проекти в практиката си и това е едно от нещата, които наистина не харесвам.
Тези и вероятно други причини карат организациите да избират хибридни подходи в разработката на софтуер, защото намират гъвкавата методология за твърде крайна и неефективна в големи организации, а аз съм работил в такива в последните повече от 15 години, така че вероятно възгледите ми са изкривени от тази перспектива.

Аз съм 'напреднал потребител'

Това ми беше писано от представител на поддръжката. Случи се след като поисках (и настоях) за някои прости (според мен) подобрения в софтуера предоставян и поддържан от голям доставчик, за който той работеше. То го написа в смисъл, че само аз искам тези подобрения, от което автоматично ми стана ясно, че те няма да бъдат направени. Е, ако това ме определя като "напреднал потребител", така да бъде, но съм доста разочарован, защото очаквах повече от SOHO устройство използващо софтуер със свободен и отворен код. Може да напиша отделна статия за това по-късно.

Аз съм себе си

Накрая, но не на последно място аз все още съм себе си с всичките си предимства и недостатъци като човек и професионалист. Нямам претенции да съм всичко за всеки, нямам претенции, че знам всичко и нямам претенции да съм най-опитния там. Всичко, което научих за себе си през 2018-та, беше основано на някакъв опит и съм сигурен, че ще ми помогне да стана по-добър човек и професионалист в бъдеще.