Showing posts with label MySQL. Show all posts
Showing posts with label MySQL. Show all posts

Thursday, July 8, 2021

[Docker - MySQL] วิธีการนำเข้าข้อมูลจากไฟล์ไปยังฐานข้อมูล MySQL ใน Docker Container
[Docker - MySQL] How to Import SQL File to MySQL Database in Docker Container

เราจะใช้คำสั่งดังนี้

sudo docker exec -it [container_id_or_name] mysql -u[mysql_username] -p[mysql_password] --default-character-set=utf8 [database_name] < [sql_file]
โดยที่
  • container_id_or_name เป็น ID หรือชื่อของ container
  • mysql_username เป็นชื่อผู้ใช้งานของ MySQL
  • mysql_password เป็นรหัสของผู้ใช้งานนั้น
  • database_name เป็นชื่อฐานข้อมูลที่ต้องการนำเข้าข้อมูล
  • sql_file เป็นชื่อไฟล์ SQL script สำหรับนำเข้าข้อมูล
อ่านเพิ่มเติมได้ที่ https://blog.code2now.com/2020/04/database-mysql-backup-restore-mysql.html

Wednesday, April 15, 2020

[MySQL] ระวังการใช้ mysqldump ในการ backup ฐานข้อมูลขนาดใหญ่ จะเกิดข้อผิดพลาด "Packet Too Large"
[MySQL] Warning: Using mysqldump to Backup Large Database May Cause "Packet Too Large" Error

หลังจากที่รัน mysqldump เพื่อ backup ฐานข้อมูลของโปรเจคนึง ก็เกิดข้อผิดพลาดดังนี้
mysqldump: Error 2020: Got packet bigger than 'max_allowed_packet' bytes when dumping table `failed_jobs` at row: 79
ข้อผิดพลาดข้างต้นเป็นข้อผิดพลาด Packet Too Large ที่มีระบุอยู่ใน MySQL Reference Manual ซึ่งสามารถเข้าไปอ่านเพิ่มเติมได้ที่ https://dev.mysql.com/doc/refman/5.7/en/packet-too-large.html

วิธีแก้ไขข้อผิดพลาดดังกล่าวมี 2 วิธีดังนี้
  1. เพิ่ม --max_allowed_packet=512M ตอนสั่งรัน mysqldump
  2. เพิ่ม max_allowed_packet=512M ไปในส่วนของ [mysqldump] ในไฟล์ my.cnf
หมายเหตุ 512M เป็นเพียงขนาดตัวอย่างเท่านั้น ขนาดใหญ่สุดที่เป็นไปได้ คือ 1024M

Wednesday, April 8, 2020

[Database - MySQL] วิธีการแก้ปัญหา Syntax Error เมื่อทำการสร้าง Procedure
[Database - MySQL] How to Fix Syntax Error when Creating a Procedure

สมมติว่า เราต้องการสร้าง procedure ด้วย SQL statement ข้างล่างนี้
CREATE PROCEDURE `my_procedure` (IN `_year` INT, IN `_month` INT)
    NO SQL
BEGIN
    SELECT * FROM my_table WHERE year = `_year`and month = `_month`;
END;
อย่างไรก็ตาม statement นี้ไม่สามารถรันได้ทุกฐานข้อมูล

บางฐานข้อมูลจะแสดงข้อผิดพลาดตามรูปข้างล่างนี้


[Database - MySQL] การ Backup และ Restore ฐานข้อมูล MySQL ผ่านทาง Command Line
[Database - MySQL] How to Backup and Restore MySQL Databases via Command Line

การ Backup ฐานข้อมูล MySQL

การ backup ฐานข้อมูล เราจะใช้คำสั่ง mysqldump ซึ่งเป็นโปรแกรมที่ถูกลงมาพร้อมกับ MySQL software โดยเราจะใช้คำสั่งดังนี้
mysqldump -u [username] -p [database_name] > [filename].sql
โดย option ที่ใส่ได้มีดังนี้
  • -u [username] ใช้ระบุชื่อผู้ใช้งานที่ใช้ login เข้าฐานข้อมูล
  • -p[password] ใช้ระบุรหัสผ่านที่ใช้ login เข้าฐานข้อมูล
    (ถ้าไม่ระบุ [password] ระบบจะถามรหัสเมื่อสั่งรัน)
  • -h [host] ใช้ระบุ host ของฐานข้อมูล (ถ้าไม่ระบุ ค่าจะเป็นเครื่องที่รันคำสั่ง)
  • -P [port] ใช้ระบุ port ของฐานข้อมูล (ถ้าไม่ระบุ ค่าจะเป็น 3306)

การ Restore ฐานข้อมูล MySQL

การ restore ฐานข้อมูล เราจะใช้คำสั่ง mysql ร่วมกับไฟล์ SQL ที่ได้จากคำสั่ง backup ข้างต้น โดยเราจะใช้คำสั่งดังนี้
mysql -u [username] -p --default-character-set=[charset] [database_name] < [filename].sql
โดย option ที่ใส่ได้มีดังนี้
  • -u [username] ใช้ระบุชื่อผู้ใช้งานที่ใช้ login เข้าฐานข้อมูล
  • -p[password] ใช้ระบุรหัสผ่านที่ใช้ login เข้าฐานข้อมูล
    (ถ้าไม่ระบุ [password] ระบบจะถามรหัสเมื่อสั่งรัน)
  • ---default-character-set=[charset] ใช้ระบุ character set ของข้อมูลที่จะนำเข้าฐานข้อมูล

Tuesday, March 10, 2020

[Docker - MySQL] การใช้ Docker Image MySQL โดยไม่ระบุเลขเวอร์ชั่นของ Patch ใน Tag อาจทำให้ได้ Docker Image เวอร์ชั่นที่เราไม่ได้คาดการณ์ไว้
[Docker - MySQL] Using Docker Image MySQL without Patch Version Number in Tag May Cause Using Unpredictable Docker Image Version

หลังจากที่ใช้ Docker Image สำหรับ MySQL 5.7 มาหลายโปรเจค 

วันนึงมีโปรเจคที่ต้องรัน SQL เพื่อ insert ข้อมูลภาษาไทยลงฐานข้อมูล ปรากฏว่า SQL ดังกล่าวสามารถรันบน environment ที่เป็น  UAT ได้ แต่ไม่สามารถรันบน Production ได้ ทั้งที่โค้ดและเลข Tag ของ Docker Image ก็เป็นเวอร์ชั่นเดียวกัน

หลังจากหาสาเหตุอยู่นาน พบว่า ถึงแม้จะใช้เลข Docker Tag เดียวกัน คือ 5.7 แต่เวอร์ชั่นของ MySQL ภายในแต่ละ Docker Image แตกต่างกัน ดังรูปข้างล่าง

Image mysql:5.7 ที่ถูกสร้างวันที่ 12/12/2017 จะใช้ MySQL version 5.7.20

[Docker - MySQL] วิธีการหลีกเลี่ยงกรณีที่ไม่สามารถรัน mysql:5.7 container ได้ เนื่องจากมีข้อผิดพลาด "Operating system error number 22 in a file operation"
[Docker - MySQL] Workaround for mysql:5.7 Container Cannot Start Due to "Operating system error number 22 in a file operation"

เนื่องจากมีหลายโปรเจคที่ใช้ฐานข้อมูลเป็น MySQL ผมจึงรัน MySQL Docker ผ่านทาง Docker Compose (บน Docker Toolbox ของ Windows) เพื่อใช้เป็นฐานข้อมูล ซึ่งจะมีการตั้งค่าในส่วน mysql service ใน docker-compose.yml ตามด้านล่างนี้
mysql:
    container_name: mysqlserver
    image: mysql:5.7
    ports:
        - 3306:3306
    volumes:
        - ./mysql:/var/lib/mysql
อย่างไรก็ตาม ปัญหานึงที่ผมเจอ คือ Container ของ MySQL จะหยุดการทำงาน เมื่อรันไปสักพัก เมื่อตรวจสอบ Log ของ Container จะเจอ error ดังนี้
2020-03-06T08:39:40.454013Z 0 [ERROR] InnoDB: Operating system error number 22 in a file operation.
2020-03-06T08:39:40.454196Z 0 [ERROR] InnoDB: Error number 22 means 'Invalid argument'
2020-03-06T08:39:40.454258Z 0 [ERROR] InnoDB: File ./ib_logfile101: 'aio write' returned OS error 122. Cannot continue operation
2020-03-06T08:39:40.454584Z 0 [ERROR] InnoDB: Cannot continue operation.
จากการตรวจสอบเบื้องต้นยังไม่สามารถหาวิธีแก้ไขได้ แต่มีวิธีการหลีกเลี่ยง error ข้างต้นไม่ให้เกิดขึ้น  โดยแก้ไขการตั้งค่าในส่วน mysql service ใน docker-compose.yml ดังนี้
mysql:
    container_name: mysqlserver
    image: mysql:5.7
    ports:
        - 3306:3306
    # volumes:
    #     - ./mysql:/var/lib/mysql

Thursday, November 28, 2019

[Laravel - Model] การตั้งค่า Attribute ของ Model ให้เป็น Lower Case
[Laravel - Model] How to Set Model Attribute to Lower Case

บางครั้งเราจำเป็นต้องทำระบบที่เชื่อมต่อกับฐานข้อมูลเดิมที่มีอยู่แล้ว และฐานข้อมูลเหล่านั้นอาจจะมีชื่อ column เป็นตัวพิมพ์ใหญ่ทั้งหมด เวลาใช้งานแต่ละ column จะต้องพิมพ์ชื่อเป็นตัวพิมพ์ใหญ่ ทำให้ยากต่อการเขียนโค้ด

สำหรับ Laravel แล้ว เราสามารถตั้งค่าเพื่อให้เปลี่ยนชื่อ column พวกนี้เป็นตัวพิมพ์เล็ก เมื่อเราเรียกใช้งานได้

วิธีการตั้งค่า

  1. เข้าไปที่ config/database.php
  2. เพิ่มโค้ดข้างล่างในส่วนของ connections ที่ต้องการ
  3. 'options' => extension_loaded('pdo_mysql') ? array_filter([
        PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
        PDO::ATTR_CASE => PDO::CASE_LOWER,
    ]) : [
        PDO::ATTR_CASE => PDO::CASE_LOWER,
    ],
    

Thursday, August 29, 2019

[Laravel - Exception] ระวังข้อผิดพลาด "Prepared statement contains too many placeholders" หากมีการ Bulk Insert ข้อมูลจำนวนมาก
[Laravel - Exception] Warning: "Prepared statement contains too many placeholders" Exception if Bulk Insert Large Data

การทำ bulk insert หรือการ insert ข้อมูลทีละเยอะๆ สามารถช่วยลดจำนวนการยิง query หลายๆรอบได้ ซึ่งส่งผลให้เวลาในการทำงานลดลงอย่างเห็นได้ชัด โดยเฉพาะอย่างยิ่ง เมื่อ Database อยู่คนละเครื่อง Server

แต่... อย่าเพิ่งคิดนะครับว่า เราจะยิงข้อมูลเป็นก้อนใหญ่ๆไปเลยทีเดียวได้

เพราะว่ามันก็มี limit ในเรื่องของ placeholder อยู่เหมือนกัน ซึ่งถ้าหากเราส่งข้อมูลก้อนใหญ่เกินไปก็จะได้ error นี้กลับมา
PDOException: SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders in /var/www/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:77
แล้ว placeholder มาจากไหน?

Tuesday, April 23, 2019

[Database - SQL] วิธีการ Query หา Record ที่มีค่ามากที่สุดหรือน้อยที่สุด
[Database - SQL] How to Query a Record that Has Maximum or Minimum Value

สมมติว่า user_login เป็นตารางในฐานข้อมูลที่มีคอลัมน์ login_at สำหรับเก็บวันเวลาที่ผู้ใช้งาน login เข้าใช้งานระบบ

ในกรณีที่เราต้องการหา record ของการ login เข้าใช้งานล่าสุดของผู้ใช้งานทุกคน (login_at มีค่ามากที่สุด) เราสามารถใช้คำสั่ง SQL ตามด้านล่างนี้ได้เลย
SELECT * 
FROM user_login 
WHERE EXISTS (
    SELECT 1
    FROM user_login AS ul
    GROUP BY user_id
    HAVING user_id = users_login.user_id AND
        MAX(login_at) = user_login.login_at
)
ในทางตรงกันข้าม ถ้าเราต้องการหา record ของการ login เข้าใช้งานครั้งแรกสุดของผู้ใช้งานทุกคน (login_at มีค่าน้อยที่สุด) เราสามารถใช้คำสั่ง SQL ตามด้านล่างนี้ได้เลย
SELECT * 
FROM user_login 
WHERE EXISTS (
    SELECT 1
    FROM user_login AS ul
    GROUP BY user_id
    HAVING user_id = users_login.user_id AND
        MIN(login_at) = user_login.login_at
)

Tuesday, January 15, 2019

[Laravel - Model] การแปลง Query Builder ไปเป็น SQL Query String
[Laravel - Model] How to Convert Query Builder to SQL Query String

สาเหตุที่ต้องแปลง Query Builder ไปเป็น SQL Query String ก็มีหลายสาเหตุด้วยกัน เช่น การ debug query ที่เกิด error ขึ้น เป็นต้น ซึ่งสามารถใช้โค้ดได้ตามด้านล่างนี้
$sql= str_replace(array('?'), array('\'%s\''), $query->toSql());
$sql = vsprintf($sql, $query->getBindings());
เมื่อ $query คือ Query Builder และ $sql คือ Query String ที่ได้จากการแปลง

Friday, December 7, 2012

[AS3] วิธีการใส่ข้อมูลลงไปยัง MySQL
[AS3] How to Insert Data into MySQL

AS3 ไม่สามารถเชื่อมต่อกับ MySQL ได้โดยตรง AS3 จำเป็นจะต้องส่งค่าตัวแปรไปยัง PHP แล้วใช้ PHP ในการเชื่อมต่อและใส่ค่าลงไปใน MySQL
AS3 cannot connect to MySQL directly. Data must be sent to PHP then PHP connect and insert data to MySQL.


[AS3] วิธีโหลดตัวแปรจาก MySQL
[AS3] How to Load Variables from MySQL

AS3 ไม่สามารถโหลดตัวแปรจาก MySQL ได้โดยตรง ตัวแปรจะต้องถูกโหลดผ่านทาง PHP หลักการทำงานคือ AS3 จะทำการเรียกและจัดเก็บข้อมูลผลลัพธ์จากหน้า PHP โดยที่ PHP จะทำการเชื่อมต่อและดึงค่าจาก MySQL แล้วทำการพิมพ์ผลลัพธ์ออกมาทางหน้าเว็บตามรูปแบบข้อความสำหรับการโหลดตัวแปรของ AS3 
AS3 cannot load variables from MySQL directly. The variables must be loaded by using PHP to get data from MySQL. The principle is AS3 call and get the results from PHP page, PHP connect and retrieve data from MySQL then print the results in correct format for loading variables in AS3