24 Ağustos 2022 Çarşamba

Docker ve MySQL

Giriş
Burada sadece "Docker" kullanarak MySQL veri tabanını çalıştırma örnekleri var. "Docker Compose" için Dockerfile ve MySQL yazısına bakabilirsiniz.

Docker ile MySQL'i çalıştırmak için belirtilen parametreler şöyle
MYSQL_ROOT_PASSWORD
MYSQL_DATABASE
Çalıştırılacak SQL dosyaları "docker-entrypoint-initdb.d" dizini altına kopyalanır.  Bu dosyalara
01-schema.sql
02-user.sql
03-data.sql 
gibi isimlere verilir

1. docker run Kullanımı
Örnek
Şöyle yaparız
docker pull mysql:5.6

docker run --name my-mysql 
  -p 3306:3306 
  -e MYSQL_ROOT_PASSWORD=mypassword 
  -d mysql:5.6
Örnek - SQL Çalıştırmak
Şöyle yaparız. 
- "docker stop mysql" yapınca container otomatik silinir. 
- Çalıştırılacak SQL dosyaları  "docker-entrypoint-initdb.d" dizini altına kopyalanır. 
- ${PWD} hem Linux hem de PowerShell ile çalışır. 
- Ayrıca mysql sunucusuna --sql-mode="ANSI_QUOTES" ile de parametre geçeriz
docker run -d -it  -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=db \
  --name mysql \
  --rm \
  -p 3306:3306 \
  -v ${PWD}/schema.sql:/docker-entrypoint-initdb.d/schema.sql \
  mysql:8.0 --sql-mode="ANSI_QUOTES"
Örnek
Şöyle yaparız
docker run -it -e MYSQL_ROOT_PASSWORD=secretpswd \
  -e MYSQL_DATABASE=blog \
  --name blog-mysql \
  -p 3307:3306 \
  mysql:8.0
Örnek - /etc/mysql/conf.d Dosyasını Belirtmek
Elimizde şöyle bir mysql config dosyası olsun
$ cat mysql-conf/jiramysql/conf.d/my-custom.conf 
[mysqld]
default-storage-engine=INNODB
character_set_server=utf8mb4
innodb_default_row_format=DYNAMIC
innodb_log_file_size=2G
sql_mode=NO_AUTO_VALUE_ON_ZERO
Çalıştırmak için şöyle yaparız
$ docker pull mysql
$ sudo docker run --detach --name=jiramysql --env="MYSQL_ROOT_PASSWORD=password" 
  --publish 6603:3306 
  --volume=/Users/cpandey/Development/Docker/mysql-data:/var/lib/mysql 
  --volume=/Users/cpandey/Development/Docker/mysql-conf/jiramysql/conf.d:/etc/mysql/conf.d mysql
Bash açmak için şöyle yaparız
$ sudo docker exec -it jiramysql bash
bash-4.4# mysql -uroot -ppassword

mysql> ...
Mount edilen volume'lara bakmak için şöyle yaparız
$ sudo docker inspect jiramysql|grep -A 16 -i mounts
             "Mounts": [
            {
                "Type": "bind",
                "Source": "/Users/cpandey/Development/Docker/mysql-data",
                "Destination": "/var/lib/mysql",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
                "Source": "/Users/cpandey/Development/Docker/mysql-conf/jiramysql/conf.d",
                "Destination": "/etc/mysql/conf.d",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
2. Dockerfile Dosyası Kullanımı
Örnek - SQL Çalıştırmak
Şöyle yaparız
ADD db_backup.sql docker-entrypoint-initdb.d/db_backup.sql
Örnek - SQL Çalıştırmak
Çalıştırılacak SQL "docker-entrypoint-initdb.d" dizini altına kopyalanır. Şöyle yaparız
FROM mysql:5.7.25
LABEL "Project"="vproject"
LABEL "Author"="Onumaku chibuike"

ENV MYSQL_ROOT_PASSWORD="vprodbpass"
ENV MYSQL_DATABASE="accounts"


ADD db_backup.sql docker-entrypoint-initdb.d/db_backup.sql

23 Ağustos 2022 Salı

ISNULL metodu

Giriş
Açıklaması şöyle
Syntax : ISNULL(expression, value)

The ISNULL() function returns a specified value if the expression is NULL. If the expression is NOT NULL, this function returns the expression.
Örnek
Şöyle yaparız
SELECT ISNULL('Hello world', 'Bye'); //Hello world
SELECT ISNULL(NULL, 500); //500



IIF metodu

Giriş
Açıklaması şöyle
The IIF() function returns a value if a condition is TRUE, or another value if a condition is FALSE.
Örnek
Şöyle yaparız
SELECT IIF('hi' = 'bye', 'YES', 'NO'); //NO

CURRENT_USER metodu

Örnek
Şöyle yaparız
SELECT CURRENT_USER; //demo

22 Ağustos 2022 Pazartesi

SET

Örnek
Şöyle yaparız
SET optimizer_switch='index_merge=off,index_merge_intersection=off';

Vitess

Giriş
Vitess Youtube içinde Go programlama dili ile geliştirilmiş. Şeklen şöyle

Aslında vttablet MySQL sunucusundan farklı bir bilgisayar üzerinde de çalışabilir ancak bu çoğu zaman gereksiz.

Ne Zaman Kullanışlı
Veri tek bir MySQL sunucusuna sığmıyorsa birden fazla veri tabanını tek bir sunucu gibi kullanmak için çok kullanışlı.

Vites master-master kullanılamaz. Açıklaması şöyle
Vitess does not support master-master replication: https://vitess.io/docs/overview/scalability-philosophy/#no-active-active-replication

If zero downtime is your primary concern, then I recommend looking to Percona Xtradb Cluster or Mysql Group Replication, but these require very reliable network between cluster nodes and can easily cause more issues then solve if used incorrectly.

Bileşenler
Bunlar şöyle

vttablet
Vitess VtTablet Nedir? yazısına taşıdım

vtgate
Vitess VtGate Nedir? yazısına taşıdım

topo
Açıklaması şöyle.
Distributed key/value store
- Stores the state of vitess : schemas, shards, sharding scheme, tablets, roles etc.
- etcd/consul/zookeeper
- Small dataset, mostly cached by vtgate
vtctld
Vitess vtctld komutu - Topology Server yazısına taşıdım

Vreplication VStream
Vitess Vreplication yazısına taşıdım


cell
Açıklaması şöyle
- A group of servers and network infrastructure
- A failure domain : isolated from failures in other cells
- Examples : 
 - a full data center
 - a subset of data center, aka availability zone
 - a Kubernetes cluster
keyspace
Açıklaması şöyle
- logical database
- If no sharding, keyspace => single MySQL database
- If using sharding, keyspace => multiple MySQL databases (all with identical schema)
- In either case, a keyspace appears as a single database from the standpoint of the application
keyspace ID
Açıklaması şöyle
- Interval to vitess, the application does not need to know anything about it
- Not stored, computed
Vschema
Shard'ın nasıl olacağını belirtir. Json dosyasıdır. SQL ile belirtilemediği için gerekir.

Vindex - Sharding Kullanıyorsak Gerekir
Açıklaması şöyle
- A way to compute  keyspace ID for any row in a table
- Vindex for a table is defined by 
  - Column name
  - Sharding function name
Açıklaması şöyle. Yani kısaca hangi shard'e erişilmesi gerektiğini belirtir.
A VIndex is Vitess’ concept of a distributed index. Much as a database index uses information within the query to find the row you’re looking for efficiently, a VIndex uses that same information to find the correct shard.
Açıklaması şöyle.
Another interesting problem was VIndexes didn’t support NULL fields.
Lookup VIndex  - Sharding Kullanıyorsak Gerekir
Açıklaması şöyle
A Lookup VIndex is a special VIndex that’s backed by a database table and intended to solve this very problem. The way it works is quite simple: the eggs table would be configured at the Vitess level to have a Lookup VIndex, let’s call it eggs_egg_id_lookup. This would correspond to a table that has an egg_id and dino_id column. Now whenever the eggs table is changed, the lookup table will be updated to have the appropriate pair of fields. Now, when you perform your query, Vitess knows that there’s a VIndex on the eggs tables’ egg_id column and will consult it to find the dino_id associated with it.
Sharding functions
Açıklaması şöyle
- binary
- binary_md5 - VARBINARY için kullanlır
- hash - BIGINTiçin kullanılır
- numeric
- numeric_static_map
- unicode_loose_md5 - text, varchar sütun için kullanılır
- reverse_bits
Shard'ın farklı cell'lerde olması tercih edilir

CREATE TABLE
Açıklaması şöyle. Yani tüm vtablet'lere dağıtılır
Use the standard MySQL CREATE TABLE syntax. The query goes through the same migration flow as ALTER TABLE does. The tablets eventually run the query directly on the MySQL backends.
Örnek - Unsharded Table
Şöyle yaparız
CREATE TABLE name_user_idx(name VARCHAR(128), user_id BIGINT, PRIMARY KEY(name, user_id));
VSchema için şöyle yaparız. Burada sharded false deniliyor ve tablo isimleri sıralanıyor
{
  "sharded": false,
  "tables": {
    "name_user_idx": {}
  }
}
Örnek - Sharded Table
Şöyle yaparız
CREATE TABLE user(user_id BIGINT,name VARCHAR(128), PRIMARY KEY(user_id));
VSchema için şöyle yaparız.  Burada sharded true deniliyor ve vindex isimleri sıralanıyor. vindex hangi sharding metodunun kullanılacağını belirtir. Daha sonra tablolar belirtiliyor ve column_vindexes ile hangi sütunun hangi vindex ile eşleceği belirtiliyor.
{
  "sharded": true,
  "vindexes": {
    "hash": {
      "type": "hash"
    }
  },
  "tables": {
    "user": {
      "column_vindexes": [
        {
          "column": "user_id",
          "name": "hash"
        }
      ]
    }
  }
}
Helm
Örnekler burada. Açıklaması burada

Sequence
vttablet için açıklama şöyle
If a select next... is received, the sequence specific functionality will be triggered.
Her sequence için bir tablo yaratılır. Sequence tabloları unsharded olmak zorundadır.

Örnek
sql dosyasında şöyle yaparız
CREATE TABLE customer_seq(id BIGINT, next_id BIGINT, cache BIGINT, PRIMARY KEY(id))
  COMMENT 'vitess_sequence';
INSERT INTO customer_seq(id, next_id, cache) VALUES(0, 1, 3);
Açıklaması şöyle
Note the special comment vitess_sequence. This instructs vttablet that this is a special table.

The table needs to be pre-populated with a single row where:

- id must always be 0
- next_id should be set to the next (starting) value of the sequence
- cache is the number of values to cache before updating the table for the next value. This value should be set to a fairly large number like 1000. We have set the value to 3 mainly to demonstrate how the feature works.
- İlk sütun niye hep 0 anlamadım. 
- İkinci sütun başlangıç değeri, 
- Üçüncü sütun ise sanırım bir seferde kaç tane değer çekileceğini belirtir. Böylece bazı değerler önceden ayrılabilir.
- Sequence için cycle özelliğini tanımlamak sanırım mümkün değil. 

vchema.json dosyasında sequence tanımlamak için şöyle yaparız
{
  "sharded": false,
  "tables": {
    "product": {},
    "customer_seq": { "type": "sequence" },
    "corder_seq": { "type": "sequence" },
    "corder_event_seq": { "type": "sequence" },
    "corder_keyspace_idx": {}
  }
}
Açıklaması şöyle
Since this is a special table, we have to inform the vschema by giving it a sequence type.
"customer_seq": { "type": "sequence" }
vchema.json dosyasında sequence kullanmak için şöyle yaparız
{
  "sharded": true,
  "vindexes": {
    ...
  },
  "tables": {
    "customer": {
      "column_vindexes": [{
        "column": "customer_id",
        "name": "hash"
      }],
      "auto_increment": {
        "column": "customer_id",
        "sequence": "product.customer_seq"
      }
    },
    ...
    }
  }
}
Eğer SQL ile sequence değerini çekmek istersek şöyle yaparız
SELECT NEXT VALUE FROM customer_seq;
Bir diğer farklı kullanım şöyle
/* Returns the next value for the sequence */
SELECT NEXT VALUE FROM my_sequence;

/* Returns the next value for the sequence, and also reserve 4 values after that. */
SELECT NEXT 5 VALUEs FROM my_sequence;
Örnek
Sharded keyspace içinde 3 tane tablo olsun
CREATE TABLE `puppers` (
  `id` bigint(22) NOT NULL,
  `name` varchar(256) DEFAULT NULL,
  `image` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE `ratings` (
  `id` bigint(22) DEFAULT NULL,
  `user_id` bigint(22) DEFAULT NULL,
  `rating` bigint(20) DEFAULT NULL,
  `pupper_id` bigint(22) DEFAULT NULL,
  KEY `pupper_id` (`pupper_id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

CREATE TABLE `users` (
  `id` bigint(22) NOT NULL,
  `email` varchar(64) DEFAULT NULL,
  `password` varbinary(256) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
Bu tablolar için json dosyası verelim ve kullanılacak sequence'ları belirtelim. Şöyle yaparız
{
  "sharded": true,
  "vindexes": {
    "binary_md5_vdx": { "type": "binary_md5" },
    "hash_vdx": { "type": "hash" }
  },
  "tables": {
    "puppers": {
      "columnVindexes": [{ "column": "id", "name": "hash_vdx" }],
      "autoIncrement": { "column": "id", "sequence": "pupper_seq" }
    },
    "ratings": {
      "columnVindexes": [{ "column": "pupper_id", "name": "hash_vdx" }],
      "autoIncrement": { "column": "id", "sequence": "rating_seq" }
    },
    "users": {
      "columnVindexes": [{ "column": "id", "name": "binary_md5_vdx" }]
    }
  }
}
Daha sonra sequence tablolarını yaratalım
CREATE TABLE IF NOT EXISTS pupper_seq (
  id INT,
  next_id BIGINT,
  cache BIGINT,
  PRIMARY KEY(id)
) comment 'vitess_sequence';

INSERT INTO pupper_seq (id, next_id, cache) VALUES (0, 1, 3); 

CREATE TABLE IF NOT EXISTS rating_seq (
  id INT,
  next_id BIGINT,
  cache BIGINT,
  PRIMARY KEY(id)
) comment 'vitess_sequence';

INSERT INTO rating_seq (id, next_id, cache) VALUES (0, 1, 3);
Sequence için kullanılacak keyspace unsharded tanımlanmalı. Şöyle yaparız
{
  "sharded": false,
  "tables": {
    "pupper_seq": {
      "type": "sequence"
    },
    "rating_seq": {
      "type": "sequence"
    }
  }
}


15 Ağustos 2022 Pazartesi

UTF-8 Desteği

Giriş
Eskiden varsayılan "character encoding" utf8 idi. Ancak artık utf8mb4
Yani özetlersek CREATE TABLE ile 
CHARACTER SET olarak utf8mb4 ve COLLATE olarak utf8mb4_general_ci kullanmak lazım

utf8 vs. utf8mb4
Açıklaması şöyle
The core reason for the separation of utf8 and utf8mb4 is that UTF-8 is different from proper UTF-8 encoding. That's the case because UTF-8 doesn't offer full Unicode support, which can lead to data loss or even security issues. UTF-8's failure to fully support Unicode is the real kicker - the UTF-8 encoding needs up to four bytes per character, while the "utf8" encoding offered by MySQL only supports three. See the issue on that front? In other words, if we want to store smilies represented like so:

We cannot do it - it's not that MySQL will store it in a format of "???" or similar, but it won't store it altogether and will respond with an error message like the following:
Incorrect string value: '\x77\xD0' for column 'demo_column' at row 1

With this error message, MySQL is saying "well, I don't recognize the characters that this smiley is made out of. Sorry, nothing I can do here" - at this point, you might be wondering what is being done to overcome such a problem. 
...
That workaround is called "utf8mb4". utf8mb4 is pretty much the same as its older counterpart - utf8 - it's just that the encoding uses one to four bytes per character which essentially means that it's able to support a wider variety of symbols and characters.
Collation
Collation yani metinlerin sıralanması
1. Veri tabanı seviyesinde
2. Tablo seviyesinde
3. Sütun seviyesinde
yapılabilir

utf8_general_ci collation
Character encoding olarak utf8 kullanıyorsak varsayılan collation utf8_general_ci

utf8mb4_general_ci collation
Character encoding olarak utf8mb4 kullanıyorsak varsayılan collation utf8mb4_general_ci
Açıklaması şöyle. Burada ci uzantısı "case insensitive" anlamına geliyor. Yani sorting ve comparison işlemlerinde bu kullanılıyor
- utf8mb4_general_ci is geared towards a more "general" use of MySQL and utf8. This character set is widely regarded to take "shortcuts" towards data storage which may result in sorting errors in some cases to improve speed.
utf8mb4_general_ci kullanılınca karşılaşılan hatalardan birisi unique constraint hatası. Açıklaması şöyle
That is, "Fred" and "freD" are considered equal at the database level. If you have a unique constraint on a field, it would be illegal to try to insert both "aa" and "AA" into the same column, since they compare as equal (and, hence, non-unique) with the default collation. If you want case-sensitive comparisons on a particular column or table, change the column or table to use the utf8_bin collation.

Şöyle yaparız
CREATE DATABASE demo_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE tests;

CREATE TABLE demo_tbl (
  'archtype_field' VARCHAR(100) DEFAULT NULL
) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
utf8mb4_unicode_ci collation
Açıklaması şöyle. Burada ci uzantısı "case insensitive" anlamına geliyor. Yani sorting ve comparison işlemlerinde bu kullanılıyor
 utf8mb4_unicode_ci is geared towards "advanced" users - that is, it's a set of collations that is based on Unicode and we can rest assured that our data will be dealt with properly if this collation is in use.


CREATE EVENT - Scheduled Task İçindir

Örnek Şöyle yaparız CREATE EVENT myevent     ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR     DO       UPDATE myschema.mytable SET myc...