Năm vấn đề chung về cơ sở dữ liệu trên PHP

Thảo luận trong 'SQL' bắt đầu bởi dinhvinh07, 19 Tháng mười 2011.

  1. Offline

    dinhvinh07

    • Friends

    • Tâm Bất Biến Giữa Dòng Đời Vạn Biến!
    Số bài viết:
    337
    Đã được thích:
    269
    Điểm thành tích:
    220
    Vấn đề 1: Sử dụng MySQL trực tiếp

    Liệt kê 1. Access/get.php
    Hãy lưu ý việc sử dụng hàm mysql_connect để truy cập vào cơ sở dữ liệu. Cũng chú ý truy vấn trong đó có dùng sự liên kết chuỗi để bổ sung tham số $name vào truy vấn đó.
    Kỹ thuật này có hai sự lựa chọn tốt: mô đun PEAR DB và các lớp PHP Data Objects (PDO-Các đối tượng dữ liệu PHP). Cả hai đều cung cấp sự trừu tượng từ việc lựa chọn của một cơ sở dữ liệu cụ thể. Do đó, mã của bạn có thể chạy mà không cần điều chỉnh quá nhiều trên IBM® DB2®, MySQL, PostgreSQL, hoặc cơ sở dữ liệu khác bất kỳ mà bạn muốn kết nối đến.
    Các giá trị khác trong việc sử dụng các tầng trừu tượng của mô đun PEAR DB và PDO là bạn có thể sử dụng toán tử ? trong các câu lệnh SQL của bạn. Việc này làm cho SQL dễ dàng bảo trì hơn và bảo vệ ứng dụng của bạn khỏi các cuộc tấn công nội xạ SQL.
    Mã thay thế khi sử dụng PEAR DB được hiển thị dưới đây.

    Liệt kê 2. Access/get_good.php
    Chú ý rằng tất cả các đề cập trực tiếp của MySQL đã diễn ra, trừ chuỗi kết nối cơ sở dữ liệu trong $dsn. Ngoài ra, chúng ta sử dụng biến $name trong SQL thông qua toán tử ?. Sau đó, dữ liệu với truy vấn này được gửi đi thông qua array ở cuối phương thức query().

    Vấn đề 2: Không sử dụng chức năng tăng tự động
    Giống như hầu hết các cơ sở dữ liệu hiện đại, MySQL có khả năng tạo các trình nhận dạng (identifier) duy nhất tăng tự động trên một cơ sở cho mỗi bản ghi. Mặc dù vậy, chúng ta vẫn thấy mã lần đầu tiên chạy một lệnh SELECT để tìm mã nhận dạng (id) tối đa, sau đó bổ sung thêm một vào id đó, cũng như một bản ghi mới. Liệt kê 3 cho thấy một lược đồ mẫu bad (xấu).

    Liệt kê 3. Badid.sql

    Trường id ở đây được quy định đơn giản là một số nguyên. Vì vậy, mặc dù nó sẽ là duy nhất, chúng ta có thể thêm vào bất kỳ giá trị nào mà chúng ta muốn, như đã chỉ ra trong câu lệnh INSERT tiếp theo câu lệnh CREATE. Liệt kê 4 chỉ ra mã PHP bổ sung thêm users (những người sử dụng) vào kiểu lược đồ này.

    Liệt kê 4. Add_user.php

    Mã trong add_user.php đầu tiên thực hiện một truy vấn để tìm ra giá trị tối đa của id. Sau đó tệp này chạy một câu lệnh INSERT với giá trị id cộng thêm một. Mã này có thể không chạy thành công trong các điều kiện ganh đua (race) trên các máy chủ có một tải nặng. Hơn nữa, nó không hiệu quả.
    Vì vậy, sự thay thế là gì? Sử dụng tính năng tăng tự động trong MySQL để tạo các ID duy nhất cho mỗi lần chèn tự động. Lược đồ cập nhật được hiển thị bên dưới.

    Liệt kê 5. Goodid.php

    Chúng ta thêm cờ NOT NULL để chỉ ra rằng các trường này không rỗng (null). Chúng ta cũng đã bổ sung cờ AUTO_INCREMENT để chỉ thị rằng trường này tăng tự động, cũng như cờ PRIMARY KEY để chỉ thị trường nào là id. Những thay đổi này cho phép tăng một chút tốc độ. Liệt kê 6 cho thấy mã PHP đã cập nhật, mã này chèn users (những người dùng) vào bảng.

    Liệt kê 6. Add_user_good.php

    Thay vì nhận được giá trị id tối đa, tôi bây giờ chỉ cần sử dụng câu lệnh INSERT để chèn dữ liệu, sau đó sử dụng một câu lệnh SELECT để lấy id của bản ghi vừa mới được chèn vào. Mã này đơn giản hơn nhiều và hiệu quả hơn so với phiên bản gốc và lược đồ liên quan của nó.
    Một lựa chọn khác đối với chức năng tăng tự động của MySQL là sử dụng phương thức nextId() trong hệ thống PEAR DB. Trong trường hợp của MySQL, điều này tạo ra một bảng tuần tự mới và quản lý việc sử dụng một cơ chế khóa phức tạp. Lợi thế của việc sử dụng phương thức này là nó sẽ hoạt động trên các hệ thống cơ sở dữ liệu khác.
    Dù bằng cách nào, bạn nên sử dụng một hệ thống quản lý sự tăng các ID duy nhất cho bạn và không dựa vào hệ thống mà bạn truy vấn đầu tiên, sau đó tăng giá trị của chính bạn và thêm bản ghi. Cách tiếp cận thứ hai dễ bị ảnh hưởng theo các điều kiện ganh đua trên các trang có khối lượng cao.
    Về đầu trang
    Vấn đề 3: Sử dụng nhiều cơ sở dữ liệu
    Một khi chúng ta thấy ứng dụng mà mỗi bảng ở trong một cơ sở dữ liệu riêng biệt. Có nhiều lý do để thực hiện điều đó trong các cơ sở dữ liệu rất lớn, nhưng đối với ứng dụng trung bình, bạn không cần mức phân đoạn này. Ngoài ra, mặc dù có thể thực hiện các truy vấn liên quan trên nhiều cơ sở dữ liệu, tôi rất khuyên bạn chống lại nó. Cú pháp phức tạp hơn. Quản lý sao lưu và khôi phục lại không dễ dàng. Cú pháp có thể hoặc không thể làm việc giữa các máy cơ sở dữ liệu khác nhau. Và thật khó khăn để tiếp tục theo cấu trúc quan hệ khi các bảng được chia trên nhiều cơ sở dữ liệu.
    Vì vậy, nhiều cơ sở dữ liệu sẽ giống thế nào? Để bắt đầu, bạn cần một số dữ liệu. Liệt kê 7 cho thấy dữ liệu này được chia thành bốn tệp.

    Liệt kê 7. Các tệp cơ sở dữ liệu

    Files.sql:
    Trong phiên bản nhiều cơ sở dữ liệu của các tệp này, bạn sẽ nạp câu lệnh SQL vào trong một cơ sở dữ liệu, sau đó nạp các câu lệnh SQL users (những người sử dụng) vào cơ sở dữ liệu khác. Mã PHP để truy vấn cơ sở dữ liệu cho các tệp này liên kết với người dùng cụ thể được hiển thị dưới đây.

    Liệt kê 8. Getfiles.php

    Hàm get_user kết nối tới cơ sở dữ liệu chứa bảng của những người sử dụng và lấy ra ID cho một người dùng đã biết. Hàm get_files kết nối đến bảng các tệp và lấy ra các hàng có kết hợp với người dùng đã biết.
    Cách tốt hơn để làm tất cả những điều này là nạp dữ liệu vào một cơ sở dữ liệu, sau đó thực hiện một truy vấn, như được hiển thị bên dưới.

    Liệt kê 9. Getfiles_good.php

    Mã này không chỉ ngắn hơn mà nó cũng dễ hiểu hơn và hiệu quả hơn. Thay vì thực hiện hai truy vấn, chúng ta đang thực hiện một.
    Trong khi vấn đề này lạc điệu, chúng ta đã thấy nó trong thực tế có đủ thời gian để biết rằng tất cả các bảng phải ở trong cùng một cơ sở dữ liệu, trừ khi có một lý do cấp thiết khác.
    Về đầu trang
    Vấn đề 4: Không sử dụng các mối quan hệ
    Các cơ sở dữ liệu quan hệ không giống như các ngôn ngữ lập trình. Chúng không có kiểu mảng. Thay vào đó, chúng sử dụng các mối quan hệ giữa các bảng để tạo ra cấu trúc một-tới-nhiều giữa các đối tượng, chúng có cùng tác dụng như một mảng. Một vấn đề mà tôi đã thấy với các ứng dụng là khi các kỹ sư cố gắng sử dụng một cơ sở dữ liệu như thể nó đã là một ngôn ngữ lập trình, tạo arrays (các mảng) bằng cách sử dụng chuỗi văn bản với các trình nhận dạng tách nhau bằng dấu phẩy. Hãy xem lược đồ dưới đây.

    Liệt kê 10. Bad.sql

    Một người dùng trong hệ thống có thể có nhiều tệp. Trong một ngôn ngữ lập trình, bạn sẽ sử dụng một mảng để biểu diễn các tệp liên kết với người dùng. Trong ví dụ này, lập trình viên đã chọn để tạo ra một trường files (các tệp) chứa danh sách các id tệp được phân cách bằng dấu phẩy. Để có được một danh sách tất cả các tệp cho người dùng cụ thể, lập trình viên trước tiên phải đọc hàng từ bảng những người dùng, sau đó phân tích cú pháp văn bản của tệp và chạy một câu lệnh SELECT riêng lẻ cho mỗi tệp. Mã này được hiển thị bên dưới..

    Liệt kê 11. Get.php

    Kỹ thuật này chậm, khó bảo trì và không tận dụng tốt cơ sở dữ liệu. Giải pháp duy nhất là tái kiến trúc lược đồ này để đưa nó trở lại thành một dạng quan hệ truyền thống, như được hiển thị dưới đây.

    Liệt kê 12. Good.sql

    Ở đây, mỗi tệp có liên quan đến người dùng thông qua hàm user_id trong bảng tệp. Điều này hầu như có vẻ lạc hậu với bất kỳ ai nhìn thấy điều này như là một mảng. Chắc chắn, các mảng không tham chiếu đến đối tượng trong mảng -- thực tế, ngược lại hoàn toàn. Nhưng trong một cơ sở dữ liệu quan hệ, đây là cách những thứ này làm và lí do các truy vấn là nhanh hơn và dễ dàng hơn nhiều. Liệt kê 13 cho thấy mã PHP tương ứng.

    Liệt kê 13. Get_good.php

    Ở đây, chúng ta thực hiện một truy vấn đến cơ sở dữ liệu để nhận được tất cả các hàng. Mã này không phức tạp và nó sử dụng cơ sở dữ liệu như nó đã được dự định.
    Về đầu trang

    Vấn đề 5: Mẫu n+1
    Tôi không thể nói cho bạn biết bao nhiêu lần chúng ta đã nhìn thấy các ứng dụng lớn trong đó mã này đầu tiên lấy ra một danh sách các thực thể -- gọi là các khách hàng -- sau đó quay trở lại và lấy ra chúng từng người một để có được những chi tiết cho từng thực thể. Chúng ta gọi nó là mẫu n+1 vì đó là có bao nhiêu truy vấn sẽ được thực hiện -- một truy vấn để lấy ra danh sách tất cả các thực thể, rồi một truy vấn cho mỗi một trong n thực thể. Đây không phải là một vấn đề khi n = 10, nhưng sẽ là gì khi n = 100 hoặc n = 1000? Rồi, sự thiếu khả năng thực sự đóng góp vào. Liệt kê 14 cho thấy một ví dụ về một lược đồ như vậy.

    Liệt kê 14. Schema.sql

    Đây là lược đồ đáng tin cậy. Không có gì sai ở đây. Vấn đề là ở trong mã truy cập vào cơ sở dữ liệu để tìm tất cả các sách cho một tác giả cụ thể, như được hiển thị dưới đây.

    Liệt kê 15. Get.php

    Nếu bạn nhìn vào mã ở dưới cùng, bạn có khả năng suy nghĩ đến chính mình, "Ôi, điều này thực sự sạch sẽ." Trước tiên, nhận được id, tác giả, rồi nhận được một danh sách các cuốn sách, sau đó nhận được thông tin về mỗi cuốn sách. Chắc chắn, nó sạch sẽ -- nhưng nó có hiệu quả không? Không. Hãy nhìn xem chúng ta phải thực hiện bao nhiêu các truy vấn để lấy ra chỉ các sách của Jack Herrington. Một truy vấn để nhận được một id, một truy vấn khác để nhận được một danh sách các cuốn sách, sau đó một truy vấn cho mỗi cuốn sách. Năm truy vấn cho ba cuốn sách!
    Giải pháp này là có một hàm thực hiện một số lượng lớn truy vấn, như liệt kê dưới đây.

    Liệt kê 16. Get_good.php

    Bây giờ lấy ra danh sách yêu cầu chỉ một truy vấn, nhanh. Nó có nghĩa là tôi có khả năng sẽ phải có một số các kiểu các phương thức này với các tham số khác nhau, nhưng thực sự không có sự lựa chọn nào. Nếu bạn muốn có một ứng dụng PHP có thể so sánh được với nhau, bạn phải sử dụng hiệu quả cơ sở dữ liệu và điều đó có nghĩa là các truy vấn thông minh hơn.
    Vấn đề với ví dụ này là nó quá rõ ràng. Thông thường, các kiểu của vấn đề n+1 hay n*n nhạy cảm hơn nhiều. Và chúng chỉ xuất hiện khi người quản trị cơ sở dữ liệu chạy một trình định hình truy vấn trên hệ thống của bạn khi nó có vấn đề về hiệu năng.
    Về đầu trang

    Kết luận
    Các cơ sở dữ liệu là các công cụ mạnh và -- như tất cả các công cụ mạnh mẽ -- chúng có thể bị lạm dụng nếu bạn không biết cách sử dụng chúng cho đúng. Thủ thuật phía sau việc xác định và giải quyết các vấn đề này là hiểu rõ hơn về công nghệ bên dưới. Quá lâu, tôi đã nghe các nhà mã hóa logic nghiệp vụ than thở rằng họ không muốn phải hiểu cơ sở dữ liệu hoặc mã SQL. Họ bao bọc cơ sở dữ liệu trong các đối tượng và tự hỏi tại sao hiệu năng lại kém đến như vậy.
    Họ không nhận ra rằng sự hiểu biết SQL là nguyên tắc cơ bản để chuyển cơ sở dữ liệu từ một hoàn cảnh khó khăn thành một đồng minh mạnh. Nếu bạn sử dụng cơ sở dữ liệu hàng ngày, nhưng SQL không phù hợp với bạn, hãy đọc The Art of SQL (Nghệ thuật SQL). Đây là hướng dẫn thiết thực, được viết rõ ràng để nhận được nhiều nhất bên ngoài một cơ sở dữ liệu.
    hongoctrienkillyou117 thích bài này.

Chia sẻ trang này

Advertising: Linux system admin | nukeviet | nukeviet 4 | Upload ảnh miễn phí