วันอังคารที่ 29 มิถุนายน พ.ศ. 2553

การใช้ JOIN ใน SQL

การใช้ JOIN ใน SQL
การทำ JOIN ใน SQL คือการนำตาราง 2 ตารางมารวมกัน โดยเงื่อนไขการรวมจะมีดังนี้

INNER JOIN เลือกเฉพาะข้อมูลที่มี key ตรงกันเท่านั้นมาแสดง
OUTER JOIN นำข้อมูลทั้งหมดมาแสดงแม้ว่า key ไม่ตรงกัน
LEFT JOIN ทำการ JOIN ข้อมูลกับตารางที่อยู่ทางซ้าย
RIGHT JOIN ทำการ JOIN ข้อมูลกับตารางที่อยู่ทางขวา
ไวยากรณ์ของการ JOIN มีดังนี้

SELECT columns_list
FROM left_table { INNER | OUTER | LEFT | RIGHT } JOIN right_table
ON join_condition
WHERE select_condition
ตัวอย่าง กำหนดให้ตาราง A และ B มีข้อมูลดังนี้

TABLE_A
------------------------
id Name
------------------------
1 John
2 Susan
3 Tony
TABLE_B
------------------------
id Salary
------------------------
1 23,000
2 12,000
5 32,100
ตัวอย่าง SQL Statement:

SELECT *
FROM TABLE_A INNER JOIN TABLE_B
ON TABLE_A.id = TABLE_B.id
ผลการการ JOIN แต่ละแบบจะได้ผลดังนี้:

INNER JOIN: ผลที่ได้จะเห็นว่าข้อมูลที่ไม่ตรงทั้งใน TABLE_A และ TABLE_B จะไม่แสดง

------------------------
id Name Salary
------------------------
1 John 23,000
2 Susan 12,000

OUTER JOIN: จะได้ข้อมูลทั้งหมด เท่าที่จะแสดงได้ เช่น ใน TABLE_A มีข้อมูลของ Tony แต่ TABLE_B ไม่มีข้อมูลของ Tony (id 3) ดังนั้นข้อมูลที่ได้ จะมีข้อมูลของ Tony แสดงแต่ไม่มีข้อมูลเงินเดือนของ Tony

------------------------
id Name Salary
------------------------
1 John 23,000
2 Susan 12,000
3 Tony
5 32,100
LEFT JOIN: ข้อมูลที่ได้จะยึดข้อมูลในตารางทางซ้ายเป็นหลัก ในที่นี้ให้ TABLE_A เป็น TABLE ด้านซ้าย จะเห็นได้จากข้อมูลใน TABLE_A ซึ่งมีรายชื่อของ John, Susan และ Tony ผลที่ได้ก็จะแสดงข้อมูลของพนักงานทั้ง 3 คน แต่ข้อมูลของ Tony จะไม่มีเงินเดือนแสดง เนื่องจากไม่มีข้อมูลของ Tony อยู่ในตาราง TABLE_B

------------------------
id Name Salary
------------------------
1 John 23,000
2 Susan 12,000
3 Tony

RIGHT JOIN: หลักการจะเหมือนกับ LEFT JOIN แต่จะต่างกันตรงที่ข้อมูลที่ได้จะยึดเอาข้อมูลในตารางด้ายขวาเป็นหลัก

------------------------
id Name Salary
------------------------
1 John 23,000
2 Susan 12,000
5 32,100

เพิ่มเติม

ในกรณีที่ต้องการ Join ข้อมูลตั้งแต่ 3 table ขึ้นไป ให้เลือก Table ขึ้นมาสองอันแล้ว Join กันก่อน จากนั้นจึงค่อย Join กับ Table ที่เหลือ เช่น


SELECT Table1.id, Table2.salary, Table3.position
FROM (Table1 INNER JOIN Table2 ON Table1.id = Table2.id)
INNER JOIN Table3 ON Table1.id = Table3.id;

วันอาทิตย์ที่ 27 มิถุนายน พ.ศ. 2553

เพิ่มความเร็วการ SELECT ด้วย MySQL Query Cache

เพิ่มความเร็วการ SELECT ด้วย MySQL Query Cache

บทความนี้ขอแนะนำอีกวีธีแต่จะมีผลทั้งเซิร์ฟเวอร์ฐานข้อมูล (Database Server) เลย ด้วยการเปิดคุณสมบัติ Query Cache ของ MySQL ให้มีการเก็บ SELECT statement และผลลัพธ์ที่ได้ไว้ใน cache ซึ่งถ้าเรารันคำสั่ง SELECT ครั้งต่อไปที่มี statement เหมือนกัน MySQL จะดึงผลลัพธ์การ query มาจาก cache โดยตรง ไม่ต้องไป query จาก table มาใหม่ ทำให้ผลการค้นหาเร็วขึ้นมาก


ถ้าข้อมูลใน table มีการเปลี่ยนแปลง cache ที่เก็บไว้จะถูกลบออกไป เพื่อให้ผลลัพธ์ในการค้นหาครั้งต่อไปถูกต้อง

ทดสอบก่อนการเปิดใช้ MySQL Query Cache

ในบทความนี้จะทดสอบกับ Fedora 10 โดย MySQL ที่ติดตั้งมาในแผ่นดีวีดี ไม่ได้เปิดคุณสมบัติ Query Cache ไว้ สามารถตรวจสอบได้จากคำสั่ง SHOW Variables ใน mysql

mysql> SHOW Variables WHERE Variable_name RLIKE 'query_cache';
+------------------------------+---------+
| Variable_name | Value |
+------------------------------+---------+
| have_query_cache | YES |
| query_cache_limit | 1048576 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 0 |
| query_cache_type | ON |
| query_cache_wlock_invalidate | OFF |
+------------------------------+---------+
6 rows in set (0.00 sec)
การที่จะใช้ Query Cache ได้นั้น ตัวแปร have_query_cache ต้องเท่ากับ ‘YES’ ตัวแปร ‘query_cache_type’ เท่ากับ ‘ON’ นอกจากนี้ต้องคอนฟิกค่า query_cache_size ด้วย เพื่อจองขนาด memory เพื่อใช้เก็บ query cache ค่า 0 คือการปิดคุณสมบัติ query cache

ทดสอบรัน SELECT ก่อนการเปิด query cache

หมายเหตุ

ตัวอย่างที่ทดสอบนี้ ไม่มีการสร้าง INDEX หรือคีย์ของฟิลด์ที่ชื่อ item_name
table ที่ใช้ทดสอบมีข้อมูลประมาณ 300,000 rows
mysql> SELECT item_id, item_name FROM items WHERE item_name = 'GK809A0';
+---------+-----------+
| item_id | item_name |
+---------+-----------+
| 261351 | GK809A0 |
+---------+-----------+
1 row in set (0.21 sec)
ลองรัน SELECT หลายๆ ครั้ง ด้วยคำสั่งเหมือนกัน เวลาที่ใช้จะใกล้เคียงกันประมาณ 0.21 วินาที

คอนฟิกค่า query_cache_size

แก้ไขไฟล์ /etc/my.cnf โดยเพิ่มคอนฟิก query_cache_size ลงไป ให้อยู่ภายใต้คอนฟิกของ [mysqld] เช่นต้องการจอง memory ขนาด 32 Mbytes สำหรับทำเป็น cache ตัวอย่างคอนฟิกไฟล์จะเป็นดังนี้

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Default to using old password format for compatibility with mysql 3.x
# clients (those using the mysqlclient10 compatibility package).
old_passwords=1
query_cache_size=32M
หลังจากแก้ไขคอนฟิกไฟล์ /etc/my.cnf รันคำสั่ง service เพื่อรีสตาร์ต MySQL Server ใหม่

[root@db-server ~]# service mysql restart
Shutting down MySQL. [ OK ]
Starting MySQL. [ OK ]
ทดสอบรัน SELECT ครั้งแรกหลังเปิดการใช้ query cache

mysql> SELECT item_id, item_name FROM items WHERE item_name = 'GK809A0';
+---------+-----------+
| item_id | item_name |
+---------+-----------+
| 261351 | GK809A0 |
+---------+-----------+
1 row in set (0.23 sec)
ยังคงใช้เวลา 0.23 วินาที เพราะว่าครั้งแรกนี้ยังไม่มีข้อมูลใน cache เลย

สามารถใช้คำสั่ง SHOW STATUS เพื่อดูสถิติการใช้ cache ของ MySQL

mysql> SHOW STATUS WHERE Variable_name RLIKE 'Qcache';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 33535344 |
| Qcache_hits | 0 |
| Qcache_inserts | 1 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 1 |
| Qcache_queries_in_cache | 1 |
| Qcache_total_blocks | 4 |
+-------------------------+----------+
8 rows in set (0.00 sec)
ค่าตัวแปร Qcache_not_cached เพิ่มเป็น 1 คือการ SELECT ครั้งนี้ไม่ได้ดึงข้อมูลจาก cache และค่า Qcache_inserts เป็น 1 คือเริ่มมีการใส่ผลลัพธ์เข้าไปใน cache

ทดลองรัน SELECT อีกครั้งนึง โดยพิมพ์ statement ให้เหมือนเดิมทุกอย่าง ทั้งตัวพิมพ์ใหญ่ พิมพ์เล็ก การเว้นวรรค ต้องเหมือนกันหมด ย้ำอีกที ต้องเหมือนกันหมด เพราะ MySQL ใช้ในการเปรียบเทียบกับ statement ที่เก็บไว้ใน cache

mysql> SELECT item_id, item_name FROM items WHERE item_name = 'GK809A0';
+---------+-----------+
| item_id | item_name |
+---------+-----------+
| 261351 | GK809A0 |
+---------+-----------+
1 row in set (0.00 sec)
เวลาที่ใช้กลายเป็น 0.00 วินาทีไปเลย เพราะว่าผลลัพธ์จากการ SELECT ครั้งนี้ MySQL ไปดึงมาจาก cache แทน

เราสามารถตรวจสอบว่าผลลัพธ์จากการ SELECT มาจาก cache โดยดูค่า Qcache_hits ที่เพิ่มขึ้น จากคำสั่ง SHOW STATUS

mysql> SHOW STATUS WHERE Variable_name RLIKE 'Qcache';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 33535344 |
| Qcache_hits | 1 |
| Qcache_inserts | 1 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 1 |
| Qcache_queries_in_cache | 1 |
| Qcache_total_blocks | 4 |
+-------------------------+----------+
8 rows in set (0.00 sec)

การเพิ่มความเร็วในการหาข้อมูลของ MySQL ด้วยวิธีการทำ Index

การเพิ่มความเร็วในการหาข้อมูลของ MySQL ด้วยวิธีการทำ Index

สวัสดีครับ ผมเขียนบทความนี้ขึ้นมาเนื่องจาก พบว่า Database ที่ผมใช้งานอยู่ Select ข้อมูลมาค่อนข้างช้า และผมก็ใช้วิธีการ Set Index เพิ่มเข้าไป มันก็สามารถทำงานได้เร็วขึ้นมากทีเดียว ก็เลยลองเขียนมาให้อ่านกันดู เผื่อใครเจอปัญหาทำนองนี้อยู่

ปกติแล้วหลังจากเขียนโปรแกรม php ที่ใช้กับ database MySQL เสร็จเรียบร้อยแล้ว ก็มักจะจบตรงนั้น พอใช้งานซักพัก ก็จะเริ่มพบปัญหาว่าทำไม ใช้ไปเรื่อยๆ มันก็ช้ามากขึ้น ซึ่งก็ต้องมาทำการจูนกันนิดหน่อย โดยการสร้าง Index ในบทความนี้ผมขอยกตัวอย่างว่า ผมใช้ table 1 อันก็แล้วกัน โดยมี field ดังข้างล่าง

idINT10(Primary)
fname VARCHAR30(Primary)
lname VARCHAR30(Primary)
salaryINT10(Primary)


แล้วเกิดผมอยากจะ Select ข้อมูลว่าให้แสดงพนักงานที่มีเงินเดือนมากกว่า 5,000 บาทโดยใช้คำสั่งข้างล่าง

select * from emp where salary>5000;

ในกรณีนี้ MySQL จะทำ full table scan คือ จะทำการอ่านข้อมูลจากทุก record ว่าตรงตามเงื่อนไขหรือเปล่า ซึ่งเราสามารถตรวจสอบดูได้ โดยใช้คำสั่ง

explain select * from emp where salary>5000;

ผลลัพธ์ที่ได้จะเป็นดังนี้

tabletypepossible_keyskey key_len ref rows Extra
empALL 2073 where used


โดยช่อง table จะแสดงว่าชื่อ table ของ record ที่ถูกดึงข้อมูลมาคือ table อะไร ในตัวอย่างนี้คือ table ที่ชื่อ emp
ช่อง type จะแสดง วิธีการอ่านข้อมูลจาก table นั้น ในที่นี้ ALL หมายถึง database จะอ่านมาทุก record เพื่อนำมาเปรียบเทียบกับเงื่อนไข where
rows หมายถึงจำนวน row ที่ถูกอ่านขึ้นมา
ซึ่งหลังจากที่เรามีการ set index ที่ field salary แล้วทำการตรวจสอบอีกครั้งด้วยคำสั่ง

explain select * from emp where salary>5000;

จะได้ผลลัพธ์ดังนี้

tabletypepossible_keyskey key_len ref rows Extra
emprefsalarysalary10const 1247


โดย type จะเปลี่ยนจาก ALL มาเป็น ref ซึ่งหมายถึง database จะดึงมาเฉพาะ row ที่มีเงื่อนไขตรงกับ index ที่ set ไว้
possible_keys คือ index key ที่อาจจะใช้สำหรับการทำคำสั่งนี้
key คือ index key ที่ใช้จริงๆสำหรับการทำคำสั่งนี้
rows คือ จำนวน row ที่อ่านขึ้นมา ซึ่งพบว่าในกรณีนี้จะมีการ row ขี้นมาน้อยกว่าตอนที่อ่านขึ้นมาทั้งหมด ซึ่งก็จะช่วยให้ database ติดต่อกับ I/O น้อย ลง ก็จะช่วยให้การทำงานเร็วขึ้น

จริงๆแล้ว เนื้อหาเกี่ยวกับการใช้คำสั่ง explain ก็มีอยู่อีกพอสมควร เช่น ในกรณีที่มีการทำ join กันหลายๆ table ซึ่งในส่วนนี้จะมีการกล่าวเอาไว้ ใน manual ของ MySQL อยู่แล้ว

วันอาทิตย์ที่ 20 มิถุนายน พ.ศ. 2553

windows firewall เปิดไม่ได้

ทำยังไงดี เปิด Windows Firewall ใน Control Panel ไม่ได้ (http://www.zealzonecafe.com/board/index.php?topic=30.msg40#msg40)

เปิด service ของ Windows Fiewall ไม่ได้

ซึ่งอาจจะมีผลทำให้เรา ping หาเครื่อง ๆ นั้นไม่เจอ

วิธีแก้ไข ให้ทำการ Rebuilding the WMI Repository มีดังนี้
========================================
สำหรับ Windows XP Service Pack 2
คลิ๊ก Start, Run แล้วพิมพ์คำสั่ง

• rundll32 wbemupgd, UpgradeRepository

------------------------
สำหรับ Windows Server 2003
คลิ๊ก Start, Run แล้วพิมพ์คำสั่ง

• rundll32 wbemupgd, RepairWMISetup

------------------------
สำหรับ Windows versions อื่น ๆ
คลิ๊ก Start, Run แล้วพิมพ์คำสั่ง CMD.EXE กด Enter เข้า command prompt

พิมพ์คำสั่ง
• net stop winmgmt

เปิด Windows Explorer, เพื่อเปลี่ยนโฟลเดอร์ %windir%\System32\Wbem\Repository. (ยกตัวอย่างเช่น, %windir%\System32\Wbem\Repository_bad.). %windir% ใช้แทน path ไปยังไดเร็คทอรี่ของ Windows , ซึ่งมักจะเป็น C:\Windows.

กลับไปที่หน้าต่าง Command Prompt , แล้วพิมพ์คำสั่งด้านล่างแล้วกด Enter ทีละคำสั่ง

• net start winmgmt

• EXIT


ทีนี้กลับไปที่ Control Panel ท่านก็จะสามารถเปิด service ของ Windows Firewall ได้แล้วครับ