1 คะแนน โดย GN⁺ 3 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • การเพิ่ม STRICT ต่อท้ายคำจำกัดความของตารางช่วยป้องกันข้อผิดพลาดด้านชนิดข้อมูล เช่น ข้อความใด ๆ ถูกใส่ลงในคอลัมน์จำนวนเต็ม ได้ตั้งแต่เนิ่น ๆ และช่วยเพิ่ม ความสมบูรณ์ของข้อมูล
  • แม้จะตรวจสอบชนิดข้อมูลตอนแทรกและอัปเดต แต่ค่าที่แปลงได้โดยไม่สูญเสียข้อมูล เช่น '123' จะยังได้รับอนุญาต และชนิดของคอลัมน์ถูกจำกัดไว้ที่ INT, INTEGER, REAL, TEXT, BLOB, ANY
  • สำหรับคอลัมน์ที่ต้องเก็บหลายชนิดข้อมูล สามารถระบุเป็น ANY ได้ ทำให้ใช้ทั้งการตรวจสอบที่เข้มงวดและการจัดเก็บที่ยืดหยุ่นในตารางเดียวกันได้
  • ไม่สามารถเปลี่ยนตารางเดิมให้เป็น STRICT ได้โดยตรง จึงต้อง สร้างตารางใหม่และคัดลอกข้อมูล และข้อมูลเดิมที่ผิดพลาดต้องถูกจัดระเบียบหรือแปลงชนิดข้อมูลก่อน
  • ตาราง STRICT รองรับเฉพาะใน SQLite 3.37.0 ขึ้นไป และแม้ในเชิงทฤษฎีจะมีต้นทุนจากการตรวจสอบ แต่การทดลองแบบไม่เป็นทางการไม่พบความแตกต่างด้านประสิทธิภาพหรือขนาดไฟล์อย่างชัดเจน

การสร้างตาราง STRICT

  • ตาราง STRICT ของ SQLite ใช้การตรวจสอบชนิดข้อมูลที่เข้มงวดขึ้น คล้ายกับเอนจิน SQL อื่น ๆ
  • เพียงเติม STRICT ไว้ท้ายคำจำกัดความ CREATE TABLE
CREATE TABLE people (name TEXT) STRICT;

การตรวจสอบชนิดข้อมูลในการแทรกและอัปเดต

  • ตาราง SQLite ทั่วไปสามารถเก็บข้อความอย่าง 'garbage' ลงในคอลัมน์ INTEGER ได้ แต่ตาราง STRICT จะถือว่า ชนิดข้อมูลไม่ตรงกัน เป็นข้อผิดพลาด
CREATE TABLE people_nonstrict (age INTEGER);
INSERT INTO people_nonstrict (age) VALUES ('garbage');
-- 정상 처리됨

CREATE TABLE people_strict (age INTEGER) STRICT;
INSERT INTO people_strict (age) VALUES ('garbage');
-- 오류: cannot store TEXT value in INTEGER column
  • การตรวจสอบแบบเดียวกันนี้ใช้กับ UPDATE ด้วย จึงป้องกันชนิดข้อมูลที่ไม่ถูกต้องได้แม้ตอนเปลี่ยนค่าหลังบันทึกแล้ว
  • อย่างไรก็ตาม หากค่าสามารถแปลงได้โดยไม่สูญเสียข้อมูล ตาราง STRICT ก็ยังอนุญาต
    • สตริง '123' สามารถแปลงเป็นจำนวนเต็ม 123 ได้อย่างสมบูรณ์ ดังนั้นการแทรกสองรายการด้านล่างจึงถูกประมวลผลเหมือนกัน
INSERT INTO people_strict (age) VALUES ('123');
INSERT INTO people_strict (age) VALUES (123);

ข้อจำกัดด้านชนิดข้อมูลในขั้นตอนกำหนดตาราง

  • ในตารางทั่วไป สามารถใช้ชื่อชนิดข้อมูลที่ SQLite ไม่รองรับในการประกาศคอลัมน์ได้
    • GARBAGE, DATETIME, JSON, UUID, BLOBB ล้วนถูกยอมรับ
    • การประกาศเช่นนี้อาจเกิดจากการพิมพ์ผิดหรือความเข้าใจผิดเกี่ยวกับ ชนิดข้อมูลที่ SQLite รองรับ
  • ตาราง STRICT จะเกิดข้อผิดพลาดในขั้นตอนสร้าง หากใช้ชื่อชนิดข้อมูลที่ไม่รองรับ
CREATE TABLE tbl (name GARBAGE) STRICT;
CREATE TABLE tbl (name DATETIME) STRICT;
CREATE TABLE tbl (name JSON) STRICT;
CREATE TABLE tbl (name UUID) STRICT;
CREATE TABLE tbl (name BLOBB) STRICT;
  • ชนิดคอลัมน์ที่อนุญาตมีเพียง INT, INTEGER, REAL, TEXT, BLOB, ANY เท่านั้น
  • ต้องระบุชนิดข้อมูลให้ทุกคอลัมน์ จึงไม่สามารถละเว้นชนิดข้อมูลเหมือน CREATE TABLE tbl (name) ได้

คงความยืดหยุ่นด้วย ANY

  • หากต้องเก็บข้อมูลที่มีชนิดไม่แน่นอน สามารถใช้คอลัมน์ ANY ได้
  • แม้อยู่ในตาราง STRICT คอลัมน์ ANY ก็สามารถเก็บชนิดข้อมูลใด ๆ ได้ ทั้งจำนวนเต็ม ข้อความ จำนวนจริง BLOB ฯลฯ
CREATE TABLE tbl (value ANY) STRICT;

INSERT INTO tbl (value) VALUES (123);
INSERT INTO tbl (value) VALUES ('text');
INSERT INTO tbl (value) VALUES (12.34);
INSERT INTO tbl (value) VALUES (X'8647');

การย้ายตารางเดิม

  • ไม่มีวิธีใช้ ALTER เพื่อเปลี่ยนตารางเดิมที่ไม่เข้มงวดให้เป็นตาราง STRICT ได้โดยตรง ดังนั้นการสร้างให้เข้มงวดตั้งแต่ต้นจึงง่ายกว่า
  • หากต้องการแปลงตารางเดิม ต้องทำตามขั้นตอน สร้างตาราง STRICT ใหม่ → คัดลอกข้อมูล → แทนที่ตารางเดิม
CREATE TABLE new_people (name TEXT) STRICT;
INSERT INTO new_people SELECT * FROM people;
DROP TABLE people;
ALTER TABLE new_people RENAME TO people;
  • หากข้อมูลเดิมมีชนิดผิด เช่น มีข้อความอยู่ในคอลัมน์จำนวนเต็ม อาจเกิดข้อผิดพลาดระหว่างการคัดลอก
    • ก่อนย้ายข้อมูล อาจต้องจัดระเบียบข้อมูลหรือแปลงชนิดด้วย CAST
  • การใช้นโยบายให้เฉพาะตารางใหม่เป็น STRICT ก็ทำได้ แต่จะทำให้แต่ละตารางมี ระดับความเข้มงวดในการตรวจสอบ ต่างกัน และอาจคาดเดาพฤติกรรมได้ยากกว่ากรณีที่ทุกตารางผ่อนปรนเหมือนกัน

กรณีที่ชนิดข้อมูลแบบยืดหยุ่นเหมาะสม

  • ทีมพัฒนา SQLite ได้สรุป ข้อดีของชนิดข้อมูลแบบยืดหยุ่น แยกไว้ และยกตัวอย่างกรณีที่พฤติกรรมเริ่มต้นมีประโยชน์
  • การใช้งานที่ตารางไม่เข้มงวดอาจสมเหตุสมผลมีดังนี้
    • ที่เก็บคีย์-ค่าแบบล้วน ๆ ที่เก็บหลายชนิดข้อมูลตามเดิม
    • พื้นที่สำหรับเก็บคุณสมบัติอื่น ๆ ที่มีชนิดต่างกัน
    • กรณีนำเข้า CSV ที่ไม่สะอาดโดยตรง และต้องรักษาแม้แต่ค่าที่ไม่ถูกต้องไว้โดยไม่ให้สูญหาย
  • อย่างไรก็ตาม ชนิดข้อมูลที่ไม่คาดคิดอาจก่อให้เกิดบั๊กที่สังเกตได้ยาก ดังนั้นในตารางทั่วไป การให้เกิดข้อผิดพลาดทันทีจึงมักดีกว่าการอนุญาตแบบเงียบ ๆ
  • ในซอร์สของ SQLite มี คอมเมนต์ที่เรียกตารางไม่เข้มงวดว่า legacy ด้วย แต่ยากจะถือเป็นหลักฐานที่น่าเชื่อถือกว่าคู่มือทางการ

ความเข้ากันได้ของเวอร์ชัน

  • ตาราง STRICT ถูกนำเข้ามาใน SQLite 3.37.0 ซึ่งเปิดตัวในเดือนพฤศจิกายน 2021
  • SQLite เวอร์ชันก่อนหน้านี้ไม่สามารถใช้ตาราง STRICT ได้
  • เวอร์ชันเก่าอ่านฐานข้อมูลที่มีตาราง STRICT อยู่ไม่ได้เช่นกัน
    • หากสร้างตาราง STRICT ด้วย SQLite รุ่นใหม่ แล้วเปิดฐานข้อมูลเดียวกันด้วย SQLite 3.36.0 จะเกิดข้อผิดพลาด

ประสิทธิภาพและพื้นที่จัดเก็บ

  • ตาราง STRICT มีการตรวจสอบชนิดข้อมูลเพิ่มเติมตอนแทรกและอัปเดต ดังนั้นในทางทฤษฎีอาจช้ากว่า
  • ในการทดลองแบบไม่เป็นทางการที่แทรกหลายล้านแถวลงในตารางที่มี 100 คอลัมน์ คอมพิวเตอร์หลายเครื่องล้วนไม่พบ ความแตกต่างด้านประสิทธิภาพที่ชัดเจน
  • ขนาดไฟล์ฐานข้อมูลบนดิสก์ก็เท่ากัน แต่เนื่องจากไม่ใช่เบนช์มาร์กอย่างละเอียด จึงอาจมีความแตกต่างที่ยังไม่ถูกพบ
  • การป้องกันไม่ให้ค่าที่ไม่ตรงกับความชอบของคอลัมน์ (column affinity) ถูกบันทึกโดยไม่ได้ตั้งใจ อาจทำให้ประสิทธิภาพดีขึ้นแทนได้เช่นกัน แต่ยังไม่มีการตรวจสอบแยกต่างหาก

สิ่งที่ควรพิจารณาเมื่อนำไปใช้

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

1 ความคิดเห็น

 
GN⁺ 3 시간 전
ความเห็นจาก Hacker News
  • เนื่องจาก SQLite ไม่มีฟีเจอร์ ALTER ตารางเพื่อเปลี่ยนเป็น strict mode ได้ จึงต้องคัดลอกข้อมูลจากตารางแบบไม่ strict ไปยังตารางแบบ strict และจากจุดนี้เองจึงได้เพิ่มความสามารถในการแปลงไปกลับทั้งสองทางใน sqlite-utils 4.1
    ใน CLI ใช้ได้ด้วย uvx sqlite-utils transform data.db mytable --strict และใน Python ใช้ db.table("mytable").transform(strict=True)
    ดู release note ได้ที่ https://sqlite-utils.datasette.io/en/stable/changelog.html#v..., เอกสาร Python API ที่ https://sqlite-utils.datasette.io/en/stable/python-api.html#..., และเอกสาร CLI ที่ https://sqlite-utils.datasette.io/en/stable/cli.html#transfo...

  • https://sqlite.org/flextypegood.html อธิบายว่าทำไม flexible typing ถึงเป็นค่าเริ่มต้น และมีแนวโน้มว่าจะไม่เปลี่ยนในอนาคต แต่ก็ไม่ตรงกับประสบการณ์จริง
    ต่างจากคำอธิบายที่ว่าแม้ใส่ชื่อลูกค้าลงใน Customer.creditScore ซึ่งเป็นจำนวนเต็ม ก็ยังตรวจพบและแก้ไขได้ง่าย แต่ในความเป็นจริง แถวข้อมูลที่เสียหายนั้นกู้คืนได้ยาก และข้อมูลอาจหายไปหมดแล้วก็ได้
    และก็เห็นด้วยได้ยากมากกับตรรกะที่ว่าการตรวจชนิดข้อมูลแบบเข้มงวดจะกันได้แค่ข้อผิดพลาดที่หาได้ง่าย จึงกลับทำให้การตรวจจับและแก้บั๊กยากขึ้น

    • มุมมองที่ว่า ความปลอดภัยและความน่าเชื่อถือ จากการตั้งค่าฐานข้อมูลที่เชื่อถือได้ จะกลับทำให้การแก้บั๊กข้อมูลยากขึ้นนั้นเข้าใจได้ยาก
      ใน Postgres มักจะเพิ่มการตรวจสอบและกลไกป้องกันให้มากที่สุดเท่าที่ทำได้ เพื่อจะได้ไม่ต้องมานั่งไล่หาข้อผิดพลาดที่ไม่ควรเกิดตั้งแต่แรกในภายหลัง
    • MongoDB ก็เคยมีตรรกะคล้ายกันว่าเก็บอะไรก็ได้ แต่คนส่วนใหญ่พอใช้งานจริงแล้วก็ตระหนักว่านี่มักเป็นคุณสมบัติที่ไม่ดี
      สิ่งนี้ดูเหมือนจะเป็นผลจากยุคสมัยที่ SQLite ถูกสร้างขึ้นและความเชื่ออันแรงกล้าของผู้เขียน มากกว่าจะเป็นหลักวิศวกรรมที่เคร่งครัด และหลังถูกวิจารณ์อย่างหนักก็ให้ความรู้สึกเหมือนพยายามหาเหตุผลอะไรมารองรับเพื่อยืนกรานจุดยืนเดิม
      แม้ Postgres จะให้ความยืดหยุ่นที่ต้องการได้ผ่านชนิดข้อมูลอย่าง JSON หรือ HSTORE แต่การให้ผู้ใช้เลือกใช้เมื่อจำเป็น แทนที่จะบังคับให้การกำหนดชนิดแบบไร้ขีดจำกัดเป็นค่าเริ่มต้น ย่อมดีกว่าแทบทุกครั้ง
  • อยากให้ STRICT เป็นค่าเริ่มต้น
    นอกจากจุดนี้แล้ว ผู้พัฒนา SQLite ก็เป็นคนที่ยอดเยี่ยมและสร้างเครื่องมือที่สุดยอดมาก

    • แม้แต่ foreign key ก็ยังไม่เปิดใช้เป็นค่าเริ่มต้น ต้องใช้ PRAGMA foreign_keys = ON;
      ปัญหาใหญ่กว่าคือสำหรับ strict table ไม่มี pragma ที่เทียบเท่ากัน ทำให้ต้องเติม STRICT ซึ่งไม่เป็นมาตรฐานลงในทุก CREATE TABLE
      มีการพิจารณา global STRICT pragma ด้วย แต่สุดท้ายก็ไม่ได้ทำจริง โดยดูข้อมูลที่เกี่ยวข้องได้ที่ https://sqlite.org/foreignkeys.html และ https://sqlite.org/forum/forumpost/1b9d073a37ca5998
    • SQLite ให้ความสำคัญกับ backward compatibility จึงแทบไม่เปลี่ยนค่าเริ่มต้นเลย
      เพื่อหลีกเลี่ยงกรณีที่ซอฟต์แวร์สำหรับ SQLite 3.53 อัปเกรดเป็น 3.54 แล้ว CREATE TABLE กลับสร้าง strict table ขึ้นมาแบบกะทันหัน ทำให้เกิด error และระบบพังทั้งชุด
    • ข้อจำกัด foreign key ก็มีปัญหาคล้ายกันที่ถูกปิดไว้เป็นค่าเริ่มต้นด้วยเหตุผลด้านความเข้ากันได้
      เลยชวนให้สงสัยว่าช่วงหนึ่ง SQLite อาจรองรับแค่ไวยากรณ์ foreign key แต่ยังไม่ได้ลงมือทำฟังก์ชันจริงหรือไม่
    • ควรมี ชนิดข้อมูลวันที่และ timestamp ที่เหมาะสม ไม่ใช่แค่สตริงธรรมดา
    • ไม่มีเหตุผลที่ฐานข้อมูลควรยอมให้ใส่ชนิดข้อมูลผิดโดยไม่ตั้งใจได้ และปรัชญาเรื่อง type safety ของ SQLite ก็น่าเสียดาย
      เคยต้องจัดการโค้ดที่ถูก deploy ไปยังอุปกรณ์หลายพันเครื่อง ซึ่งเก็บสตริง '1' และ '0' ลงในคอลัมน์ boolean และการตามเก็บกวาดเรื่องนี้ก็ไม่สนุกเลย
      อีกทั้งยังไม่มีชนิดข้อมูล timestamp ทำให้ต้องเก็บในคอลัมน์ข้อความ และแม้แต่ฟังก์ชันวันที่/เวลามาตรฐานก็ยังสร้าง yyyy-mm-dd HH:MM:SS ที่ต้องตีความเองโดยปริยายว่าเป็น UTC แทน yyyy-mm-ddTHH:MM:SSZ ซึ่งเป็นรูปแบบ ISO
      SQLite เป็นโปรเจ็กต์ที่ยอดเยี่ยมจริง ๆ แต่การตัดสินใจด้านการออกแบบบางอย่างก็น่าฉงน
  • จากมุมมองของสภาพแวดล้อม SQL สำหรับองค์กร เดิมทีผมไม่เคยมอง SQLite อย่างจริงจังเพราะมันไม่ได้บังคับชนิดข้อมูลของฟิลด์โดยปริยาย และก็ยังแปลกใจตอนที่มันกลายเป็นฐานของเมตาดาตาในแอปสมาร์ตโฟน
    มันทำให้นึกถึงเรื่องเล่าเก่า ๆ ในโลกเครือข่ายที่เลือกใช้ UDP เพราะ latency ต่ำและเรียบง่าย แล้วสุดท้ายก็ต้องกลับไปสร้าง ความน่าเชื่อถือแบบ TCP เองในระดับแอปพลิเคชันเกือบทั้งหมด

    • ถ้าลงมือทำเอง ก็อาจออกแบบให้ต่างจาก TCP ได้ และบางครั้งก็ได้ผลลัพธ์ที่ดีมาก ซึ่ง QUIC และ HTTP/3 ก็เป็นตัวอย่าง
      แต่การไปทำ type checking เองบน SQLite ที่ไม่ strict ดูแล้วไม่น่าจะได้ข้อดีแบบเดียวกัน
    • foreign key นั้นก่อนปี 2009 ยังไม่รองรับเลย และจนถึงตอนนี้ก็ยังไม่ได้เปิดใช้งานเป็นค่าเริ่มต้น: https://sqlite.org/foreignkeys.html
    • บางทีก็มีคนทำแนวทางแบบนี้จนประสบความสำเร็จทางธุรกิจจริง: https://aeron.io/
    • ถ้าไม่มีการรองรับ type checking อย่างครบถ้วน ก็พอเข้าใจได้ว่าทำไมบางคนถึงไม่มอง SQLite อย่างจริงจัง แต่ฐานข้อมูลส่วนใหญ่เองก็ไม่ได้มีค่าเริ่มต้นที่สมบูรณ์แบบทั้งหมด
      PostgreSQL ก็เช่นกัน ค่าเริ่มต้นถูกตั้งมาเผื่อเครื่องสเปกต่ำ ดังนั้นถ้าจะรีดประสิทธิภาพสูงสุดก็ยังต้องปรับแต่ง
      อีกอย่าง TCP เป็นแบบ stream-based จึงมีปัญหา HOL blocking ในหลายแอปพลิเคชัน และถ้าคุณสร้าง reliability layer เองบน UDP ก็มีโอกาสได้ผลลัพธ์ที่ดีกว่า TCP หลังจากลงแรงไปมาก
    • ถ้าคุณสนใจ Jeep หรือ Bronco คุณก็คงไม่ไปหานักวิจารณ์รถทั่วไป
      เพราะคนเหล่านั้นจะบอกว่ามันเสียงดังและบังคับยาก ทั้งที่จริง ๆ แล้วมันถูกออกแบบมาเพื่อการใช้งานอีกแบบ แต่กลับถูกตัดสินจาก use case ของคนวิจารณ์เอง
  • ตารางแบบ strict มีข้อเสียตรงที่ ใช้บางชนิดข้อมูลอย่าง Date ไม่ได้ แต่ถึงอย่างนั้นมันก็ควรเป็นค่าเริ่มต้น
    ถ้ามีหลายแอปพลิเคชันใช้ฐานข้อมูลร่วมกัน ก็ควรเชื่อถือชนิดข้อมูลที่ประกาศไว้ได้ และถ้าแอปหนึ่งเก็บสตริงลงในคอลัมน์ตัวเลข แอปที่เหลือก็พังหมด
    ในทางกลับกัน กรณีใช้งานหลักของ SQLite คือฐานข้อมูลแบบ embedded ซึ่งมักมีแอปเดียวใช้ จึงมีข้อดีตรงที่สามารถค่อย ๆ พัฒนาสคีมาได้แทนที่จะต้องสร้างฐานข้อมูลใหม่แล้วคัดลอกข้อมูล
    ในกรณีนี้ โค้ดของแอปพลิเคชันย่อมรู้อยู่แล้วว่าควรคาดหวังอะไรจากแต่ละคอลัมน์ แม้จะมีชนิดข้อมูลปะปนกันก็ตาม

    • SQLite มี ชนิดข้อมูล 5 แบบ เท่านั้นคือ INTEGER, TEXT, BLOB, REAL, NUMERIC: https://sqlite.org/datatype3.html
    • SQLite ไม่มีชนิดข้อมูลวันที่ และก็ไม่มีวิธีเรียก EXPLAIN กับ SELECT แบบใดก็ได้เพื่อดึงชื่อชนิดข้อมูลที่ระบุไว้ตามรูปแบบออกมา
      เพราะฉะนั้น ถึงจะใช้ชื่ออย่าง DATE หรือ DATETIME ก็ยังอนุมานสิ่งนั้นกลับมาไม่ได้ด้วยซ้ำ
    • Date ไม่ใช่ชนิดข้อมูลจริง แต่เป็นเพียงคอลัมน์ที่มี numeric affinity เท่านั้น
  • strict mode จำกัดการเขียนชนิดคอลัมน์ ทำให้ใช้ชื่อที่มีความหมายมากกว่าไม่ได้ และยังทำให้โค้ดไม่สามารถอาศัยชื่อเหล่านั้นตอนแมปชนิดข้อมูลของฐานข้อมูลกับชนิดข้อมูลในแอปพลิเคชันได้ จึงกลับกลายเป็นว่าขัดขวางระบบชนิดข้อมูลที่เข้มงวดกว่าที่ชั้นแอปพลิเคชัน
    รายละเอียดเพิ่มเติมอยู่ที่ https://hn.algolia.com/?query=chrismorgan+strict+sqlite&type=comment และถ้าคุณใช้งานฐานข้อมูลผ่าน crate อย่าง sqlx ของ Rust ก็มองว่าเลี่ยง strict mode จะดีกว่า

  • สำหรับฐานข้อมูลและ RPC นั้นผมต้องการ strict typing แต่ SQLite มีเป้าหมายการใช้งานต่างออกไปบ้าง และถ้าลองใช้เอง คุณอาจเข้าใจ https://sqlite.org/flextypegood.html มากขึ้น
    ตัวอย่างเช่น การตั้งเป้าให้สคริปต์ใด ๆ ที่ไม่ได้เขียนมาเพื่อ SQLite โดยเฉพาะยังพอทำงานได้โดยบังเอิญ เป็นคุณสมบัติที่ DBMS อื่น ๆ ปกติไม่ได้คำนึงถึง

    • ในเอกสารนั้น ส่วนข้อดีข้อเสียยังขาดประเด็นสำคัญไป
      ข้อดีหลักของการกำหนดชนิดข้อมูลแบบยืดหยุ่นคือ ทำให้พัฒนาสคีมาได้ง่าย
      เวลาความต้องการของฐานข้อมูลแบบ embedded เปลี่ยนไป ก็สามารถปรับสคีมาในที่เดิมได้ แทนที่จะต้องสร้างฐานข้อมูลใหม่และย้ายข้อมูล และถ้ามีแอปเดียวที่อ่านเขียนฐานข้อมูลอยู่แล้ว การมีสตริงเพิ่มเข้าไปในคอลัมน์จำนวนเต็มก็ไม่ใช่เรื่องน่าตกใจ
      ในทางกลับกัน ถ้ามีหลายแอปพลิเคชันแชร์ฐานข้อมูลเดียวกันและอัปเดตตามตารางเวลาของตัวเอง สคีมาคือสัญญา ดังนั้นชนิดข้อมูลที่ผิดเพียงจุดเดียวก็อาจทำให้อีกแอปพังได้
      ถ้าตารางที่แอปหนึ่งสร้างถูกอีกแอปนำไปใช้ ก็ต้องรักษาชนิดข้อมูลที่ตกลงกันไว้อย่างเคร่งครัด
    • โดยทั่วไปแล้ว คนส่วนมากตรวจสอบตั้งแต่ตอนคอมไพล์ว่าโค้ดทำตามโครงสร้างชนิดข้อมูลหรือไม่ และสคีมาของ SQLite ที่พัฒนาไปพร้อมกันก็ให้ข้อมูลชนิดข้อมูลที่จำเป็นต่อการวิเคราะห์แบบสถิต
      การตรวจซ้ำตอนรันไทม์แทบไม่ได้ประโยชน์จริง เพราะโค้ดที่การวิเคราะห์แบบสถิตยืนยันแล้วว่าใส่สตริง จะไม่กลายพันธุ์ขึ้นมาจนใส่จำนวนเต็มเองโดยฉับพลัน
      SQLite ต่างจาก Postgres ที่มีหลายแอปพลิเคชันแชร์ข้อมูลกันและต้องเชื่อถือบุคคลที่สาม
      ในสภาพแวดล้อมแบบ Postgres การ ตรวจสอบตอนรันไทม์ เป็นสิ่งจำเป็น แต่ SQLite โดยพื้นฐานแล้วถูกออกแบบมาสำหรับแอปหนึ่งตัวกับฐานข้อมูลหนึ่งชุด จึงต้องเชื่อถือแค่โค้ดของตัวเองที่ประเมินได้ตั้งแต่ตอนคอมไพล์
      ถ้าเป็นกรณีพิเศษที่มีหลายแอปแชร์ไฟล์เดียวกัน ก็สามารถเปิดใช้ตารางแบบ strict ได้
  • ชนิดข้อมูลแบบไดนามิกอาจเหมาะกับการใช้งานอย่าง key-value store แบบง่าย ๆ แต่ก็ควรถามว่าระหว่างการที่ INTEGER รับ 'hello world' ได้โดยไม่ error กับการที่ต้องระบุคีย์เวิร์ดอย่าง NONSTRICT หรือชนิดข้อมูล ANY อย่างชัดเจนก่อนถึงจะใส่ค่าแบบนั้นได้ แบบไหนสอดคล้องกับ หลักการไม่ทำให้ผู้ใช้ประหลาดใจโดยไม่จำเป็น มากกว่ากัน
    ผู้ใช้ SQLite ส่วนใหญ่น่าจะไม่ได้คาดว่าจะเป็นแบบแรก

    • อาจเป็นเพราะ SQLite ต้องการมุ่งไปทางฐานข้อมูลแบบไม่ยึดชนิดข้อมูลตายตัว แต่ก็อยากให้ไวยากรณ์ดูเหมือน SQL มาตรฐานด้วย
      ซึ่งก็สอดคล้องกับคำอธิบายที่ว่าอยากให้โค้ดสำหรับ DBMS อื่นมารันบน SQLite ได้โดยบังเอิญ
      ถึงอย่างนั้น ในเมื่อผู้ใช้ไม่ได้ละการระบุชนิดข้อมูล แต่เขียน INTEGER ไว้ชัดเจนแล้วกลับยังใส่ข้อความได้ นี่ก็ยังเป็นเรื่องน่าประหลาดใจมาก
  • เคยมีกรณีที่ UUID ซึ่งขึ้นต้นด้วยค่าอย่าง 08123… ถูก parse เป็นเลขฐานแปด ทำให้บางส่วนถูกแปลงเป็นตัวเลขผิด
    มันทั้งชวนสับสนและน่าหงุดหงิด แต่ก็แก้ได้ด้วยการใช้ STRICT แล้วสร้างตารางใหม่ทั้งหมด

    • นั่นไม่ใช่ SQLite แต่เป็นผลจาก language driver ที่พยายามช่วยมากเกินไป
      เพราะ SQLite ไม่มี ชนิดข้อมูลเลขฐานแปด
  • โดยพื้นฐานจะใช้ CREATE TABLE ... STRICT WITHOUT ROWID และไม่รู้ว่ามีเหตุผลอะไรที่ต้องทำให้ต่างจากนี้เป็นพิเศษ