mysqli หรือ PDO - อะไรคือข้อดีและข้อเสีย? [ปิด]


342

ในสถานที่ของเราเราแยกระหว่างการใช้ mysqli และ PDO สำหรับสิ่งต่าง ๆ เช่นคำสั่งที่เตรียมไว้และการสนับสนุนการทำธุรกรรม บางโครงการใช้หนึ่งโครงการบางโครงการใช้บางโครงการ มีความเป็นไปได้น้อยมากที่เราจะย้ายไปที่ RDBMS อื่น

ฉันชอบ PDO ด้วยเหตุผลเดียวที่ให้พารามิเตอร์ที่มีชื่อสำหรับคำสั่งที่เตรียมไว้และเท่าที่ฉันทราบ mysqli ไม่ได้

มีข้อดีและข้อเสียอื่น ๆ หรือไม่ในการเลือกข้อใดข้อหนึ่งเป็นมาตรฐานในขณะที่เรารวมโครงการของเราเพื่อใช้เพียงแนวทางเดียว


5
นี้บทความจะช่วยในการเลือกที่หนึ่งที่จะใช้ หากคุณพิจารณาประสิทธิภาพการทำงานสิ่งนี้อาจช่วยคุณเลือกได้
ravi404

3
มันตลกที่มีผู้คนมากมายที่โหวตขึ้นและติดดาวคำถามที่ว่า "ไม่สร้างสรรค์" สิ่งที่เป็นหัวข้อเต็มสร้างสรรค์มาก - บางทีผู้ดูแลควรคำนึงถึงเรื่องนี้เมื่อตัดสินว่าคำถามนั้นเป็นตัวสร้างหรือไม่?
marlar

@marlar ฉัน sooooooo เห็นด้วยกับคุณ! นี่เป็นปัญหาที่ใหญ่ที่สุดใน StackOverflow คำถาม / การอภิปรายที่ดีเยี่ยมจะปิดตัวลงเสมอ
Sliq

คำตอบ:


243

คุณสามารถโต้เถียงกับแง่มุมของวัตถุข้อความที่เตรียมไว้ความจริงที่ว่ามันกลายเป็นมาตรฐาน ฯลฯ แต่ฉันรู้ว่าส่วนใหญ่เชื่อว่าบางคนทำงานได้ดีขึ้นด้วยคุณสมบัตินักฆ่า ดังนั้นจึงเป็น:

สิ่งที่ดีจริง ๆ กับ PDO คือคุณสามารถดึงข้อมูลฉีดเข้าไปในวัตถุโดยอัตโนมัติ หากคุณไม่ต้องการใช้ORM (เพราะเป็นเพียงสคริปต์ด่วน) แต่คุณชอบการทำแผนที่วัตถุมันเจ๋งจริงๆ:

class Student {

    public $id;
    public $first_name;
    public $last_name

    public function getFullName() {
        return $this->first_name.' '.$this->last_name
    }
}

try 
{
    $dbh = new PDO("mysql:host=$hostname;dbname=school", $username, $password)

    $stmt = $dbh->query("SELECT * FROM students");

    /* MAGIC HAPPENS HERE */

    $stmt->setFetchMode(PDO::FETCH_INTO, new Student);


    foreach($stmt as $student)
    {
        echo $student->getFullName().'<br />';
    } 

    $dbh = null;
}
catch(PDOException $e)
{
    echo $e->getMessage();
}

12
มีความแตกต่างระหว่างข้างบนและ$mysqliResult->fetch_object("student");?
Andy Fleming

2
@ e-Satisfaction ไม่ฉันใช้ PHP สาขาโยธาละเมิด encapsulation ดังนั้นAS A BEST PRACTICEมันเป็นเพียงแค่ ... ฮ่า ๆ :) Google ไม่ได้ใช้สนามสาธารณะเท่านั้น accessors: google-styleguide.googlecode.com/svn/trunk/...
OZ_

6
@ e-Satis: ขออภัยที่กระโดดเข้ามา แต่จำเป็นต้องมี getters และ setters หากคุณต้องการควบคุมว่าจะเกิดอะไรขึ้นเมื่อตัวแปรเปลี่ยนแปลง ไม่เช่นนั้นคุณจะไม่สามารถรับประกันสถานะภายในของวัตถุได้ (โดยเฉพาะอย่างยิ่งปัญหานี้หากคุณมีวัตถุอื่นอยู่ภายใน) นี่เป็นภาษาที่เป็นอิสระทั้งหมด @OZ_: ทำให้ง่ายขึ้น คำติชมส่วนตัวจะทำให้คนอื่นป้องกัน
James P.

2
@monadic: เห็นด้วย การห่อหุ้มนั้นเป็นข้อโต้แย้งที่ถูกต้องเมื่อจัดการกับองค์ประกอบหลักหรือวัตถุที่ซับซ้อนเป็นต้นอย่างไรก็ตามในฐานะที่เป็นตัวแทนของบันทึกซึ่งอาจจะเป็นอ่าน - เขียนรอง อาร์เรย์นี้เป็นที่ยอมรับ นอกจากนี้ยังช่วยให้การตรวจสอบประเภทง่ายขึ้นขณะที่ระเบียนลอยผ่านระบบ
Dan Lugg

15
@outis ฉันหวังว่าฉันไม่ได้อยู่ในชนกลุ่มน้อยที่นี่ แต่ฉันไม่รู้สึกว่าคำตอบควรได้รับการพิจารณาเกี่ยวกับความปลอดภัยของพวกเขาที่มีต่อนักพัฒนาใหม่ ฟังดูรุนแรง แต่มันเป็นเรื่องจริง จุดประสงค์ของคำตอบเกี่ยวกับ SO นั้นไม่เพียง แต่จะให้รหัสการคัดลอกและวาง แต่ยังให้ความเข้าใจเช่นกัน ไม่ใช่หน้าที่ของผู้ตอบที่จะตรวจสอบให้แน่ใจว่าทุกหลุมความปลอดภัยหรือข้อบกพร่องของรูปแบบถูกครอบคลุมในตัวอย่างเนื่องจากเราจะต้องเผชิญกับมันแอปพลิเคชันที่โค้ดที่ได้รับการคัดลอกลงไปนั้นแตกต่างจากแอพพลิเคชันอื่น ๆ
Mattygabe

57

การย้ายแอปพลิเคชันจากฐานข้อมูลหนึ่งไปยังอีกฐานข้อมูลนั้นไม่ใช่เรื่องทั่วไป แต่ไม่ช้าก็เร็วคุณอาจพบว่าตัวเองทำงานในโครงการอื่นโดยใช้ RDBMS อื่น หากคุณอยู่บ้านกับ PDO อย่างน้อยก็จะมีสิ่งหนึ่งที่น้อยกว่าที่จะเรียนรู้ ณ จุดนั้น

นอกเหนือจากนั้นฉันพบ PDO API ใช้งานง่ายขึ้นเล็กน้อยและให้ความรู้สึกเชิงวัตถุมากขึ้น mysqli รู้สึกเหมือนว่ามันเป็นเพียง API ขั้นตอนที่ได้รับการคัดค้านถ้าคุณรู้ว่าฉันหมายถึงอะไร ในระยะสั้นฉันพบว่า PDO ทำงานง่ายขึ้น แต่นั่นเป็นเรื่องส่วนตัว


25

ฉันเริ่มใช้ PDO เพราะการสนับสนุนคำสั่งดีกว่าในความคิดของฉัน ฉันใช้เลเยอร์การเข้าถึงข้อมูลของ ActiveRecord-esque และมันง่ายกว่ามากในการใช้คำสั่งที่สร้างขึ้นแบบไดนามิก การผูกพารามิเตอร์ MySQLi จะต้องทำในการเรียกใช้ฟังก์ชัน / เมธอดเดียวดังนั้นถ้าคุณไม่รู้จนกระทั่งถึงรันไทม์ว่าคุณต้องการผูกพารามิเตอร์กี่ตัวคุณจะถูกบังคับให้ใช้call_user_func_array()(ฉันเชื่อว่าเป็นชื่อฟังก์ชันที่ถูกต้อง) สำหรับการเลือก . และลืมเกี่ยวกับการผูกผลลัพธ์แบบไดนามิกอย่างง่าย ๆ

ที่สำคัญที่สุดฉันชอบ PDO เพราะเป็นระดับที่สมเหตุสมผล มันใช้งานง่ายในระบบที่เป็นนามธรรมอย่างสมบูรณ์ที่คุณไม่ต้องการเขียน SQL แต่มันยังทำให้ง่ายต่อการใช้ระบบสืบค้นที่ดีที่สุดบริสุทธิ์หรือผสมทั้งสองอย่างเข้าด้วยกัน


2
ผลการสืบค้นด้วยแบบสอบถามที่สร้างขึ้นแบบไดนามิกนั้นเป็นไปได้เราดำเนินการกับแอปพลิเคชันของเรา อย่างไรก็ตามมันเป็นความเจ็บปวดอย่างมาก
Pim Jager

17

PDO เป็นมาตรฐานซึ่งเป็นสิ่งที่นักพัฒนาส่วนใหญ่คาดหวังที่จะใช้ mysqli นั้นเป็นวิธีแก้ปัญหาแบบเฉพาะเจาะจงสำหรับปัญหาเฉพาะ แต่มันมีปัญหาทั้งหมดของไลบรารีเฉพาะ DBMS อื่น ๆ PDO เป็นที่ทำงานหนักและความคิดที่ชาญฉลาดจะไป


15

นี่คือสิ่งอื่นที่จะเก็บไว้ในใจ: สำหรับตอนนี้ (PHP 5.2) ห้องสมุด PDO คือรถ มันเต็มไปด้วยแมลงประหลาด ตัวอย่างเช่น: ก่อนที่จะเก็บPDOStatementในตัวแปรตัวแปรควรunset()หลีกเลี่ยงข้อบกพร่องจำนวนหนึ่ง สิ่งเหล่านี้ส่วนใหญ่ได้รับการแก้ไขใน PHP 5.3 และจะออกในต้นปี 2009 ใน PHP 5.3 ซึ่งอาจมีข้อบกพร่องอื่น ๆ อีกมากมาย คุณควรมุ่งเน้นไปที่การใช้ PDO สำหรับ PHP 6.1 หากคุณต้องการรุ่นที่เสถียรและใช้ PDO สำหรับ PHP 5.3 หากคุณต้องการช่วยเหลือชุมชน


2
ฉันคิดว่ากำไรที่ PDO เสนอนั้นคุ้มค่าที่จะเข้าใจและแก้ไขข้อผิดพลาด PHP นั้นเต็มไปด้วยข้อผิดพลาดที่รุนแรงมากบางอย่างที่เราไม่สามารถทำได้อย่างมีประสิทธิภาพ แต่ก็มีประโยชน์มากมายที่ทำให้เราใช้มันแทนตัวเลือกอื่น ๆ
Brian Warshaw

11
เอ่อแปลกฉันไม่เคยพบข้อผิดพลาดใด ๆ กับ PDO และฉันใช้มันมาก
NikiC

Mysqli ยังมีข้อบกพร่อง ซอฟต์แวร์ทั้งหมดมีข้อบกพร่อง
Bill Karwin

10

ความแตกต่างที่น่าสังเกต (ดี) เกี่ยวกับ PDO ก็คือPDO::quote()วิธีนี้จะเพิ่มเครื่องหมายคำพูดล้อมรอบโดยอัตโนมัติในขณะที่mysqli::real_escape_string()(และ similars) ไม่:

PDO :: quote () วางเครื่องหมายคำพูดไว้รอบ ๆ สตริงอินพุต (หากจำเป็น) และหลีกเลี่ยงอักขระพิเศษภายในสตริงอินพุตโดยใช้รูปแบบการอ้างอิงที่เหมาะสมกับไดรเวอร์พื้นฐาน


8

PDO จะทำให้การปรับขยายทำได้ง่ายขึ้นหากไซต์ / แอปเว็บของคุณเป็นจริงเพราะคุณสามารถตั้งค่าการเชื่อมต่อ Master และ Slave เพื่อกระจายโหลดไปยังฐานข้อมูลได้ทุกวันและ PHP มุ่งไปสู่ ​​PDO เป็นมาตรฐาน

ข้อมูล PDO

ปรับขนาดเว็บแอปพลิเคชัน


6

ในแง่ของความเร็วของการดำเนินการ MySQLi ชนะ แต่ถ้าคุณไม่มี wrapper ที่ดีโดยใช้ MySQLi ฟังก์ชั่นที่เกี่ยวข้องกับคำสั่งที่เตรียมไว้นั้นแย่มาก

ยังคงมีข้อบกพร่องในเหมืองของฉัน แต่ถ้าใครต้องการมันก็เป็นได้ได้

ดังนั้นในระยะสั้นหากคุณกำลังมองหาความเร็วที่เพิ่มขึ้นแล้ว MySQLi; หากคุณต้องการความสะดวกในการใช้งานแล้ว PDO


2
ในแง่ของความเร็วคุณสามารถกำหนดมาตรฐานได้หรือไม่?
Julius F

8
Jonathen Robson ทำการเปรียบเทียบความเร็วที่เหมาะสมของทั้งสองที่ jonathanrobson.me/2010/06/mysqli-vs-pdo-benchmarks สรุป: inserts - เกือบเท่ากับselects - mysqli เร็วกว่า 2.5% สำหรับข้อความที่ไม่ได้จัดทำ / ~ 6.7% เร็วกว่าสำหรับข้อความที่เตรียมไว้ เมื่อพิจารณาว่าการลงโทษประสิทธิภาพมีน้อยเพียงใดคุณลักษณะและความยืดหยุ่นในการใช้PDOโดยทั่วไปจะมีมากกว่าประสิทธิภาพที่ได้รับ
Adam

1
@Adam ขอบคุณที่เชื่อมโยงไปยังบล็อกของฉัน!
jnrbsn

@ daemonfire300 นี่เป็นความจริงไม่จำเป็นต้องมีการวัดประสิทธิภาพ PDO ล้อมไลบรารี mysqli ฉันอาจจะโดนแฟนถ้าใครสามารถพิสูจน์ว่า PDO เร็วกว่า mysqli :-D
Dyin

@jnrbsn คุณเห็นด้วยกับอดัมกับสิ่งที่เขาพูด?
Basit

5

โดยส่วนตัวแล้วฉันใช้ PDO แต่ฉันคิดว่านั่นเป็นคำถามที่ชอบเป็นพิเศษ

PDO มีคุณสมบัติบางอย่างที่ช่วยให้เกิดการฉีด SQL ( คำสั่งที่เตรียมไว้ ) แต่ถ้าคุณระมัดระวัง SQL ของคุณคุณก็สามารถทำได้ด้วย mysqli เช่นกัน

การย้ายไปยังฐานข้อมูลอื่นไม่ใช่เหตุผลที่จะใช้ PDO ตราบใดที่คุณไม่ได้ใช้ "คุณสมบัติพิเศษของ SQL" คุณสามารถสลับจากหนึ่งไปยังอีกที่หนึ่ง อย่างไรก็ตามทันทีที่คุณใช้ตัวอย่างเช่น "SELECT ... LIMIT 1" คุณจะไม่สามารถไปที่ MS-SQL ซึ่งเป็น "SELECT TOP 1 ... " ดังนั้นนี่เป็นปัญหาอยู่ดี


22
MySQLi ได้เตรียมงบ
Tower

5

แก้ไขคำตอบแล้ว

หลังจากมีประสบการณ์กับ API ทั้งสองนี้แล้วฉันจะบอกว่ามีคุณลักษณะระดับการบล็อก 2 รายการซึ่งทำให้ mysqli ใช้ไม่ได้กับคำสั่งที่เตรียมมา
พวกเขาถูกกล่าวถึงแล้วใน 2 คำตอบที่ยอดเยี่ยม (ยัง underrated วิธี):

  1. ค่าการเชื่อมโยงกับจำนวนตัวยึดตำแหน่งโดยพลการ
  2. การส่งคืนข้อมูลเป็นอาร์เรย์อย่างเดียว

(ทั้งที่กล่าวถึงในคำตอบนี้ )

ด้วยเหตุผลบางอย่าง mysqli จึงล้มเหลวทั้งสองอย่าง
ทุกวันนี้มันมีการปรับปรุงบางอย่างสำหรับอันที่สอง ( get_result ), แต่มันทำงานได้เฉพาะในการติดตั้ง mysqlnd, หมายความว่าคุณไม่สามารถพึ่งพาฟังก์ชั่นนี้ในสคริปต์ของคุณได้

แต่ถึงกระนั้นก็ยังไม่มีการผูกมัดแม้กระทั่งทุกวันนี้

ดังนั้นจึงมีเพียงทางเลือกเดียวคือPDO

เหตุผลอื่นทั้งหมดเช่น

  • ชื่อตัวยึดตำแหน่ง (น้ำตาลไวยากรณ์นี้เป็นวิธี overrated)
  • รองรับฐานข้อมูลที่แตกต่างกัน (ไม่มีใครเคยใช้จริง)
  • ดึงเข้าไปในวัตถุ (เพียงน้ำตาลไวยากรณ์ไร้ประโยชน์)
  • ความแตกต่างความเร็ว (ไม่มี)

ไม่มีความสำคัญใด ๆ

ในขณะเดียวกัน API ทั้งสองนี้ยังขาดคุณสมบัติที่สำคัญบางอย่างเช่น

  • ตัวระบุตัวแทน
  • ตัวยึดตำแหน่งสำหรับชนิดข้อมูลที่ซับซ้อนเพื่อให้การเชื่อมโยงแบบไดนามิกน้อยกว่าลำบาก
  • รหัสแอปพลิเคชันที่สั้นกว่า

ดังนั้นเพื่อให้ครอบคลุมความต้องการในชีวิตจริงเราต้องสร้างห้องสมุดนามธรรมของตนเองขึ้นอยู่กับหนึ่งใน API เหล่านี้โดยใช้ตัวยึดตำแหน่งแบบแยกวิเคราะห์ด้วยตนเอง ในกรณีนี้ฉันชอบ mysqli เพราะมันมีระดับความเป็นนามธรรมที่น้อยกว่า


ในที่สุดใครบางคนที่รู้และไม่ปฏิเสธข้อเท็จจริงของชีวิต ...
Ihsan

4

ในสคริปต์มาตรฐานของฉันแต่ละวิธีจะทดสอบ 10,000 ครั้งและพิมพ์ความแตกต่างของเวลาทั้งหมดสำหรับแต่ละวิธี คุณควรใช้การกำหนดค่าของคุณเองฉันแน่ใจว่าผลลัพธ์จะแตกต่างกัน

นี่คือผลลัพธ์ของฉัน:

  • " SELECT NULL" -> PGO()เร็วขึ้น ~ 0.35 วินาที
  • " SHOW TABLE STATUS" -> mysqli()เร็วขึ้น ~ 2.3 วินาที
  • " SELECT * FROM users" -> mysqli()เร็วขึ้น ~ 33 วินาที

หมายเหตุ: โดยใช้ -> fetch_row () สำหรับ mysqli ชื่อคอลัมน์จะไม่ถูกเพิ่มเข้าไปในอาร์เรย์ฉันไม่พบวิธีที่จะทำเช่นนั้นใน PGO แต่แม้ว่าฉันจะใช้ -> fetch_array (), mysqli จะช้ากว่าเล็กน้อย แต่ก็ยังเร็วกว่า PGO (ยกเว้น SELECT NULL)


17
PGO คืออะไร และเร็วกว่า33 วินาที ! ผมพบว่ายากมากที่จะเชื่อว่า ...
อลิกซ์แอ็กเซิล

3

สิ่งหนึ่งที่ PDO มีคือ MySQLi ที่ฉันไม่ชอบคือความสามารถของ PDO ในการส่งคืนผลลัพธ์เป็นวัตถุประเภทคลาสที่ระบุ (เช่น$pdo->fetchObject('MyClass')) MySQLi fetch_object()จะส่งคืนstdClassวัตถุเท่านั้น


19
ที่จริงแล้วคุณสามารถระบุคลาสได้ด้วยตนเอง: "object mysqli_result :: fetch_object ([string $ class_name [, array $ params]])" stdClass จะใช้เฉพาะในกรณีที่คุณไม่ได้ระบุอะไรเลย
Andrioid

-4

มีสิ่งหนึ่งที่ต้องจำไว้

Mysqli ไม่สนับสนุนฟังก์ชั่น fetch_assoc () ซึ่งจะคืนค่าคอลัมน์ด้วยปุ่มที่แสดงถึงชื่อคอลัมน์ แน่นอนมันเป็นไปได้ที่จะเขียนฟังก์ชั่นของคุณเองจะทำอย่างนั้นก็ไม่ได้นานมาก แต่ผมก็มีจริงๆเวลาที่ยากเขียนมัน (สำหรับผู้ศรัทธาที่ไม่ใช่: ถ้ามันดูเหมือนง่ายให้คุณลองด้วยตัวคุณเองเวลาและ Don' t cheat :))


4
คุณลองใช้คู่มือหรือไม่ php.net/manual/en/mysqli-result.fetch-assoc.php
จนถึง

2
ใช้งานได้นานขึ้น แต่ใช่ฉันตรวจสอบคู่มือแล้ว มันทำงานกับงบเตรียม? ฉันสงสัย ...
ไมค์

2
จริงๆแล้วมันมีการสนับสนุนบางส่วนที่อยากรู้อยากเห็น คุณสามารถดึงข้อมูลอาร์เรย์ในการสืบค้นปกติ แต่ไม่อยู่ในการสืบค้นแบบพารามิเตอร์: -!
ÁlvaroGonzález

1
ทำไมไม่ลบคำตอบที่เห็นได้ชัดว่าผิด?
Majid Fouladpour

2
@MajidFouladpour - คำตอบคือไม่ผิดอย่างเห็นได้ชัด มันแค่บริบทหายไป Mysqli ไม่สนับสนุนการดึงข้อมูลอาเรย์อย่างเต็มที่
ÁlvaroGonzález
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.