Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Phương pháp hay nhất để lưu trữ trọng số trong cơ sở dữ liệu SQL?

Bạn cho rằng có những điểm không chính xác cố hữu trong số dấu phẩy động. Tôi nghĩ rằng điều này đáng được khám phá một chút trước.

Khi quyết định dựa trên hệ thống số để biểu thị một số (cho dù trên một tờ giấy, trong mạch máy tính hoặc ở nơi khác), có hai riêng biệt các vấn đề cần xem xét:

  1. cơ sở của nó ; và

  2. định dạng của nó .

Chọn một cơ sở, bất kỳ cơ sở nào…

Bị giới hạn bởi không gian hữu hạn, không thể đại diện cho một thành viên tùy ý của tập hợp vô hạn . Ví dụ:bất kể bạn mua bao nhiêu giấy hay chữ viết tay của bạn nhỏ đến mức nào, luôn có thể tìm thấy một số nguyên không vừa với khoảng trống đã cho (bạn có thể tiếp tục thêm các chữ số thừa cho đến khi hết giấy). Vì vậy, với số nguyên , chúng tôi thường giới hạn không gian hữu hạn của mình để chỉ đại diện cho những thứ nằm trong khoảng thời gian cụ thể nào đó — ví dụ:nếu chúng ta có khoảng trắng cho dấu dương / âm và ba chữ số, chúng ta có thể tự giới hạn ở khoảng [-999,+999] .

Mọi không trống khoảng thời gian chứa một tập hợp vô hạn các số thực. Nói cách khác, bất kể khoảng thời gian nào thì người ta sẽ vượt qua số thực —Có thể là [-999,+999] , [0,1] , [0.000001,0.000002] hoặc bất cứ điều gì khác — vẫn có một tập hợp thực vô hạn trong khoảng thời gian đó (người ta chỉ cần giữ các chữ số phân số phụ (khác 0))! Do đó các số thực tùy ý phải luôn luôn được "làm tròn" thành thứ gì đó có thể được biểu diễn trong không gian hữu hạn.

Tập hợp các số thực có thể được biểu diễn trong không gian hữu hạn phụ thuộc vào hệ thống số được sử dụng. Trong vị trí (quen thuộc) của chúng tôi base-10 hệ thống, không gian hữu hạn sẽ đủ cho một nửa ( 0.510 ) nhưng không dành cho một phần ba ( 0.33333…10 ); ngược lại, trong vị trí (ít quen thuộc hơn) base-9 hệ thống thì ngược lại (những con số đó tương ứng là 0.44444…9 0.39 ). Hệ quả của tất cả những điều này là một số số có thể được biểu diễn chỉ bằng một lượng nhỏ không gian trong cơ số vị trí-10 (và do đó xuất hiện rất "tròn trịa" đối với con người chúng ta), ví dụ:một phần mười, thực sự sẽ yêu cầu các mạch nhị phân vô hạn được lưu trữ chính xác (và do đó dường như không quá "tròn trịa" đối với những người bạn kỹ thuật số của chúng ta)! Đáng chú ý, vì 2 là hệ số của 10 nên điều này không đúng ngược lại:bất kỳ số nào có thể được biểu diễn bằng số nhị phân hữu hạn cũng có thể được biểu diễn bằng số thập phân hữu hạn.

Chúng tôi không thể làm tốt hơn với số lượng liên tục. Cuối cùng những đại lượng như vậy phải sử dụng một biểu diễn hữu hạn trong một số hệ thống chữ số:có thể tùy ý xem hệ thống đó có dễ dàng trên mạch máy tính, trên ngón tay con người, trên thứ gì khác hoặc không có gì cả — bất kể hệ thống nào được sử dụng, giá trị phải được làm tròn và do đó nó luôn luôn dẫn đến "lỗi đại diện".

Nói cách khác, ngay cả khi một công cụ đo lường hoàn toàn chính xác (điều này là không thể thực hiện được), thì bất kỳ phép đo nào mà nó báo cáo đều sẽ đã được làm tròn đến một số tình cờ phù hợp trên màn hình của nó (trong bất kỳ cơ số nào mà nó sử dụng — thường là số thập phân, vì những lý do rõ ràng). Vì vậy, "86,2 oz" thực ra không bao giờ là " 86,2 oz "mà là đại diện cho" cái gì đó từ 86.1500000 ... oz đến 86.2499999 ... oz ". (Thực ra, vì trên thực tế, công cụ này không hoàn hảo, tất cả những gì chúng ta có thể thực sự nói là chúng ta có một số mức độ tin cậy rằng giá trị thực tế nằm trong khoảng thời gian đó — nhưng điều đó chắc chắn khác xa thời điểm ở đây).

Nhưng chúng tôi có thể làm tốt hơn với số lượng rời rạc . Các giá trị như vậy không phải là "số thực tùy ý" và do đó không có giá trị nào ở trên áp dụng cho chúng:chúng có thể được biểu diễn chính xác trong hệ thống chữ số mà chúng đã được xác định — và thực sự, nên là (vì chuyển đổi sang một hệ thống chữ số khác và cắt bớt thành một độ dài hữu hạn sẽ dẫn đến làm tròn thành một số không chính xác). Máy tính có thể (không hiệu quả) xử lý các tình huống như vậy bằng cách biểu diễn số dưới dạng chuỗi:ví dụ:xem xét ASCII hoặc BCD mã hóa.

Áp dụng định dạng…

Vì đây là thuộc tính của cơ sở (hơi tùy ý) của hệ thống chữ số, việc giá trị có vẻ là "tròn" hay không không liên quan đến độ chính xác của nó . Đó là một quan sát thực sự quan trọng , điều này trái ngược với trực giác của nhiều người (và đó là lý do tôi đã dành rất nhiều thời gian để giải thích cơ sở số ở trên).

Thay vào đó, độ chính xác được xác định bằng số lượng số liệu quan trọng một đại diện có . Chúng tôi cần một định dạng lưu trữ có khả năng ghi lại các giá trị của chúng tôi vào ít nhất là càng nhiều số liệu quan trọng mà chúng tôi cho là đúng . Lấy ví dụ về các giá trị mà chúng tôi cho là đúng khi được nêu là 86.20.0000862 , hai tùy chọn phổ biến nhất là:

  • Điểm cố định , trong đó số lượng các con số quan trọng phụ thuộc vào độ lớn :ví dụ. trong biểu diễn 5 dấu thập phân cố định, các giá trị của chúng tôi sẽ được lưu trữ dưới dạng 86.200000.00009 (và do đó có 7 và 1 số liệu có độ chính xác tương ứng). Trong ví dụ này, độ chính xác đã bị mất ở giá trị thứ hai (và thực sự, chúng tôi sẽ không mất nhiều thời gian hơn nữa nếu chúng tôi hoàn toàn không thể đại diện cho bất cứ điều gì có ý nghĩa); và giá trị cũ được lưu trữ độ chính xác sai , điều này làm lãng phí không gian hữu hạn của chúng ta (và thực sự, sẽ không mất nhiều thời gian hơn để giá trị trở nên lớn đến mức làm tràn dung lượng lưu trữ).

    Một ví dụ phổ biến về thời điểm định dạng này có thể phù hợp với hệ thống kế toán:các khoản tiền thường phải được theo dõi đến từng xu không phân biệt độ lớn của chúng (do đó cần ít độ chính xác hơn đối với các giá trị nhỏ và độ chính xác cao hơn được yêu cầu đối với các giá trị lớn). Khi nó xảy ra, tiền tệ thường cũng được coi là rời rạc (đồng xu không thể phân chia được), vì vậy đây cũng là một ví dụ điển hình về tình huống mà một cơ sở cụ thể (số thập phân đối với hầu hết các loại tiền hiện đại) được mong muốn để tránh các lỗi biểu diễn được thảo luận ở trên.

  • Dấu chấm động , trong đó số lượng các con số quan trọng là không đổi bất kể độ lớn :ví dụ. trong biểu diễn thập phân có 5 chữ số có nghĩa, các giá trị của chúng tôi sẽ được lưu trữ dưới dạng 86.2000.000086200 (và, theo định nghĩa, có 5 số liệu quan trọng về độ chính xác cả hai lần). Trong ví dụ này, cả hai giá trị đã được lưu trữ mà không làm mất độ chính xác ; và cả hai đều có cùng số tiền của độ chính xác sai, điều này ít lãng phí hơn (và do đó chúng tôi có thể sử dụng không gian hữu hạn của mình để biểu thị phạm vi giá trị lớn hơn nhiều — cả lớn và nhỏ).

    Một ví dụ phổ biến về thời điểm định dạng này có thể thích hợp là để ghi lại bất kỳ phép đo nào trong thế giới thực :độ chính xác của dụng cụ đo lường (tất cả đều bị cả hệ thống ngẫu nhiên sai số) là khá ổn định bất kể tỷ lệ, do đó, với đủ số liệu có nghĩa (thường là khoảng 3 hoặc 4 chữ số), độ chính xác hoàn toàn không bị mất ngay cả khi thay đổi cơ số dẫn đến làm tròn thành một số khác .

    Nhưng mức độ chính xác của các định dạng lưu trữ dấu chấm động được sử dụng bởi máy tính của chúng tôi?

    Điều quan trọng nhất cần nhận ra là các định dạng này tương ứng hơn mười nghìn và hơn một nghìn tỷ lần chính xác hơn chứ không phải nói "86,2" —mặc dù các chuyển đổi chính xác của nhị phân trở lại thành số thập phân vẫn xảy ra bao gồm độ chính xác sai sai (mà chúng tôi phải bỏ qua:sẽ sớm tìm hiểu thêm về điều này)!

Cũng lưu ý rằng cả hai cố định định dạng dấu phẩy động sẽ làm mất độ chính xác khi một giá trị được biết chính xác hơn định dạng hỗ trợ. Như vậy lỗi làm tròn có thể lan truyền trong các phép toán số học để mang lại kết quả rõ ràng có sai sót (điều này không nghi ngờ gì giải thích việc bạn tham chiếu đến "tính không chính xác cố hữu" của số dấu phẩy động):ví dụ:3 × 3000 tại điểm cố định 5 vị trí sẽ mang lại 999.99000 thay vì 1000.00000; và 7 − ⁄50 trong dấu phẩy động 5 con số có nghĩa sẽ mang lại 0.0028600 thay vì 0.0028571 .

Trường phân tích số dành riêng cho việc tìm hiểu những hiệu ứng này, nhưng điều quan trọng là phải nhận ra rằng bất kỳ hệ thống có thể sử dụng (thậm chí thực hiện các phép tính trong đầu của bạn) dễ bị các vấn đề như vậy vì không có phương pháp tính toán nào được đảm bảo kết thúc có thể cung cấp độ chính xác vô hạn :ví dụ:hãy xem xét cách tính diện tích hình tròn — giá trị được sử dụng cho π nhất thiết sẽ bị mất độ chính xác, giá trị này sẽ truyền vào kết quả.

Kết luận

  1. Các phép đo trong thế giới thực phải sử dụng dấu phẩy động nhị phân :nó nhanh, nhỏ gọn, cực kỳ chính xác và không tệ hơn bất kỳ thứ gì khác (bao gồm cả phiên bản thập phân mà bạn đã bắt đầu). Vì kiểu dữ liệu dấu phẩy động của MySQL là IEEE754, đây chính xác là những gì họ cung cấp.

  2. Ứng dụng tiền tệ phải sử dụng điểm cố định denary :trong khi nó chậm và lãng phí bộ nhớ, nó đảm bảo cả hai giá trị không được làm tròn thành số lượng không chính xác và không bị mất xu khi các khoản tiền lớn. Vì kiểu dữ liệu điểm cố định của MySQL là các chuỗi được mã hóa BCD, đây chính xác là những gì họ cung cấp.

Cuối cùng, hãy nhớ rằng ngôn ngữ lập trình thường biểu diễn các giá trị phân số bằng cách sử dụng dấu phẩy động nhị phân loại:vì vậy nếu cơ sở dữ liệu của bạn lưu trữ các giá trị ở định dạng khác, bạn cần phải cẩn thận cách chúng được đưa vào ứng dụng của bạn, nếu không chúng có thể được chuyển đổi (với tất cả các vấn đề tiếp theo) tại giao diện.

Lựa chọn nào là tốt nhất trong trường hợp này?

Hy vọng rằng tôi đã thuyết phục bạn rằng các giá trị của bạn có thể an toàn (và nên ) được lưu trữ trong các kiểu dấu phẩy động mà không phải lo lắng quá nhiều về bất kỳ "sự không chính xác" nào? Hãy nhớ rằng chúng còn nhiều hơn nữa chính xác hơn so với cách biểu diễn số thập phân có 3 chữ số có nghĩa mỏng manh của bạn từng là:bạn chỉ cần bỏ qua độ chính xác sai (nhưng một điều phải luôn luôn vẫn làm điều đó, ngay cả khi sử dụng định dạng thập phân dấu chấm cố định).

Đối với câu hỏi của bạn:chọn tùy chọn 1 hoặc 2 thay vì tùy chọn 3 — nó giúp so sánh dễ dàng hơn (ví dụ:để tìm khối lượng tối đa, người ta chỉ có thể sử dụng MAX(mass) , trong khi để làm điều đó hiệu quả trên hai cột sẽ yêu cầu một số lồng).

Giữa hai thứ đó, không quan trọng cái nào chọn — số dấu phẩy động được lưu trữ với số lượng bit quan trọng không đổi bất kể tỷ lệ của chúng như thế nào .

Hơn nữa, trong trường hợp chung, có thể xảy ra trường hợp một số giá trị được làm tròn thành số nhị phân gần với cách biểu diễn thập phân ban đầu bằng cách sử dụng tùy chọn 1 trong khi đồng thời những giá trị khác được làm tròn thành số nhị phân gần với biểu diễn thập phân ban đầu hơn bằng cách sử dụng tùy chọn 2, như chúng ta sẽ sớm thấy các lỗi biểu diễn như vậy chỉ biểu hiện trong độ chính xác sai luôn luôn được bỏ qua.

Tuy nhiên, trong this trường hợp, vì nó xảy ra rằng có 16 ounce đến 1 pound (và 16 là lũy thừa của 2), sự khác biệt tương đối giữa các giá trị thập phân ban đầu và số nhị phân được lưu trữ bằng cách sử dụng hai phương pháp là giống hệt nhau :

  1. 5.387510 (không phải 5.3367187510 như đã nêu trong câu hỏi của bạn) sẽ được lưu trữ trong một float32 binary32 dưới dạng 101.0110001100110011001102 (là 5.3874998092651367187510 ):đây là 0.0000036% từ giá trị ban đầu (nhưng, như đã thảo luận ở trên, "giá trị ban đầu" đã là một biểu diễn khá tệ hại của đại lượng vật lý mà nó đại diện).

    Biết rằng số float nhị phân32 chỉ lưu trữ độ chính xác 7 chữ số thập phân, trình biên dịch của chúng tôi biết chắc chắn rằng mọi thứ từ chữ số thứ 8 trở đi đều chắc chắn là độ chính xác sai và do đó phải bị bỏ qua trong mọi case — do đó, với điều kiện là giá trị đầu vào của chúng tôi không yêu cầu độ chính xác cao hơn thế (và nếu đúng như vậy, binary32 rõ ràng là lựa chọn sai định dạng), điều này đảm bảo trả về giá trị thập phân trông giống như giá trị mà từ đó chúng tôi bắt đầu:5.38750010 . Tuy nhiên, chúng ta thực sự nên áp dụng kiến ​​thức về miền tại thời điểm này (như chúng ta nên làm với bất kỳ định dạng lưu trữ nào) để loại bỏ bất kỳ độ chính xác sai nào có thể tồn tại, chẳng hạn như hai số 0 ở cuối đó.

  2. 86.210 sẽ được lưu trữ trong một float32 binary dưới dạng 1010110.001100110011001102 (là 86.199996948242187510 ):đây cũng là 0.0000036% từ giá trị ban đầu. Như trước đây, chúng tôi sau đó bỏ qua độ chính xác sai để quay lại đầu vào ban đầu của chúng tôi.

Lưu ý cách biểu diễn nhị phân của các số giống hệt nhau, ngoại trừ vị trí của điểm cơ số (cách nhau bốn bit):

101.0110 00110011001100110
101 0110.00110011001100110

Điều này là do 5,3875 × 2 =86,2.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. INDIA, STD Code Finder Script trong PHP, MYSQL, JQUERY

  2. ngăn chặn việc chèn hàng trùng lặp trong php / mysql

  3. Có thể tạo hai khóa chính trong một bảng không?

  4. Các ràng buộc về MySQL và Kiểm tra

  5. Tạo một bảng tạm thời trong MySQL với một chỉ mục từ một lựa chọn