SQLite কর্মক্ষমতা জন্য সেরা অনুশীলন

Android SQLite, একটি দক্ষ SQL ডাটাবেসের জন্য অন্তর্নির্মিত সমর্থন অফার করে। আপনার অ্যাপের কর্মক্ষমতা অপ্টিমাইজ করতে এই সর্বোত্তম অনুশীলনগুলি অনুসরণ করুন, আপনার ডেটা বৃদ্ধির সাথে সাথে এটি দ্রুত এবং অনুমানযোগ্যভাবে দ্রুত থাকে তা নিশ্চিত করুন। এই সর্বোত্তম অনুশীলনগুলি ব্যবহার করে, আপনি কার্যক্ষমতা সংক্রান্ত সমস্যাগুলির সম্মুখীন হওয়ার সম্ভাবনাও হ্রাস করেন যা পুনরুত্পাদন করা এবং সমস্যা সমাধান করা কঠিন।

দ্রুত কর্মক্ষমতা অর্জন করতে, এই কর্মক্ষমতা নীতি অনুসরণ করুন:

  • কম সারি এবং কলাম পড়ুন : শুধুমাত্র প্রয়োজনীয় ডেটা পুনরুদ্ধার করতে আপনার প্রশ্নগুলি অপ্টিমাইজ করুন। ডাটাবেস থেকে পড়া ডেটার পরিমাণ কমিয়ে দিন, কারণ অতিরিক্ত ডেটা পুনরুদ্ধার কার্যক্ষমতাকে প্রভাবিত করতে পারে।

  • SQLite ইঞ্জিনে কাজ পুশ করুন : SQL কোয়েরির মধ্যে কম্পিউটেশন, ফিল্টারিং এবং বাছাই করার ক্রিয়াকলাপ সম্পাদন করুন। SQLite এর ক্যোয়ারী ইঞ্জিন ব্যবহার করে উল্লেখযোগ্যভাবে কর্মক্ষমতা উন্নত করতে পারে।

  • ডাটাবেস স্কিমা পরিবর্তন করুন : SQLite দক্ষ ক্যোয়ারী প্ল্যান এবং ডেটা উপস্থাপনা তৈরি করতে সাহায্য করার জন্য আপনার ডাটাবেস স্কিমা ডিজাইন করুন। সঠিকভাবে সূচী টেবিল এবং কর্মক্ষমতা উন্নত করার জন্য টেবিল কাঠামো অপ্টিমাইজ করুন।

অতিরিক্তভাবে, আপনি আপনার SQLite ডাটাবেসের কর্মক্ষমতা পরিমাপ করতে উপলব্ধ সমস্যা সমাধানের সরঞ্জামগুলি ব্যবহার করতে পারেন যাতে অপ্টিমাইজেশন প্রয়োজন এমন ক্ষেত্রগুলি সনাক্ত করতে সহায়তা করে।

আমরা জেটপ্যাক রুম লাইব্রেরি ব্যবহার করার পরামর্শ দিই।

কর্মক্ষমতা জন্য ডাটাবেস কনফিগার করুন

SQLite-এ সর্বোত্তম কর্মক্ষমতার জন্য আপনার ডাটাবেস কনফিগার করতে এই বিভাগের ধাপগুলি অনুসরণ করুন।

লিখতে-আগে লগিং সক্ষম করুন৷

SQLite মিউটেশনগুলিকে একটি লগে যুক্ত করে প্রয়োগ করে, যা এটি মাঝে মাঝে ডাটাবেসে সংকুচিত করে। একে রাইট-এহেড লগিং (WAL) বলা হয়।

WAL সক্ষম করুন যদি না আপনি ATTACH DATABASE ব্যবহার করেন।

সিঙ্ক্রোনাইজেশন মোড শিথিল করুন

WAL ব্যবহার করার সময়, ডিফল্টরূপে প্রতিটি কমিট একটি fsync ইস্যু করে যাতে তথ্যটি ডিস্কে পৌঁছে যায়। এটি ডেটা স্থায়িত্ব উন্নত করে কিন্তু আপনার প্রতিশ্রুতিকে ধীর করে দেয়।

SQLite এর সিঙ্ক্রোনাস মোড নিয়ন্ত্রণ করার একটি বিকল্প রয়েছে। আপনি যদি WAL সক্ষম করেন, সিঙ্ক্রোনাস মোড সেট করুন NORMAL :

কোটলিন

db.execSQL("PRAGMA synchronous = NORMAL")

জাভা

db.execSQL("PRAGMA synchronous = NORMAL");

এই সেটিংয়ে, একটি ডিস্কে ডেটা সংরক্ষণ করার আগে একটি কমিট ফিরে আসতে পারে। যদি একটি ডিভাইস শাটডাউন ঘটে, যেমন পাওয়ার হারানো বা কার্নেল প্যানিক হলে, প্রতিশ্রুতিবদ্ধ ডেটা হারিয়ে যেতে পারে। যাইহোক, লগিংয়ের কারণে, আপনার ডাটাবেস দূষিত হয় না।

শুধুমাত্র আপনার অ্যাপ ক্র্যাশ হলে, আপনার ডেটা এখনও ডিস্কে পৌঁছায়। বেশিরভাগ অ্যাপের জন্য, এই সেটিংটি কোনো উপাদান খরচ ছাড়াই কার্যক্ষমতার উন্নতি ঘটায়।

দক্ষ টেবিল স্কিমা সংজ্ঞায়িত করুন

কর্মক্ষমতা অপ্টিমাইজ করতে এবং ডেটা খরচ কমাতে, একটি দক্ষ টেবিল স্কিমা সংজ্ঞায়িত করুন। SQLite দক্ষ ক্যোয়ারী প্ল্যান এবং ডেটা তৈরি করে, যার ফলে দ্রুত ডেটা পুনরুদ্ধার হয়। এই বিভাগটি টেবিল স্কিমা তৈরির জন্য সর্বোত্তম অনুশীলন প্রদান করে।

INTEGER PRIMARY KEY বিবেচনা করুন

এই উদাহরণের জন্য, নিম্নরূপ একটি টেবিল সংজ্ঞায়িত করুন এবং পপুলেট করুন:

CREATE TABLE Customers(
  id INTEGER,
  name TEXT,
  city TEXT
);
INSERT INTO Customers Values(456, 'John Lennon', 'Liverpool, England');
INSERT INTO Customers Values(123, 'Michael Jackson', 'Gary, IN');
INSERT INTO Customers Values(789, 'Dolly Parton', 'Sevier County, TN');

টেবিল আউটপুট নিম্নরূপ:

সারিবদ্ধ আইডি নাম শহর
1 456 জন লেনন লিভারপুল, ইংল্যান্ড
2 123 মাইকেল জ্যাকসন গ্যারি, IN
3 789 Dolly Parton সেভিয়ার কাউন্টি, টিএন

কলাম rowid হল একটি সূচক যা সন্নিবেশের ক্রম সংরক্ষণ করে। rowid দ্বারা ফিল্টার করা প্রশ্নগুলি দ্রুত বি-ট্রি অনুসন্ধান হিসাবে প্রয়োগ করা হয়, তবে id দ্বারা ফিল্টার করা প্রশ্নগুলি একটি ধীর টেবিল স্ক্যান।

আপনি যদি id দ্বারা লুকআপ করার পরিকল্পনা করেন, আপনি সঞ্চয়স্থানে কম ডেটা এবং একটি সামগ্রিক দ্রুত ডাটাবেসের জন্য rowid কলাম সংরক্ষণ করা এড়াতে পারেন:

CREATE TABLE Customers(
  id INTEGER PRIMARY KEY,
  name TEXT,
  city TEXT
);

আপনার টেবিল এখন নিম্নরূপ দেখায়:

আইডি নাম শহর
123 মাইকেল জ্যাকসন গ্যারি, IN
456 জন লেনন লিভারপুল, ইংল্যান্ড
789 Dolly Parton সেভিয়ার কাউন্টি, টিএন

যেহেতু আপনাকে rowid কলাম সংরক্ষণ করার দরকার নেই, তাই id কোয়েরি দ্রুত হয়। উল্লেখ্য যে সারণিটি এখন সন্নিবেশ ক্রমের পরিবর্তে id উপর ভিত্তি করে সাজানো হয়েছে।

সূচী দিয়ে প্রশ্নগুলিকে ত্বরান্বিত করুন

SQLite ক্যোয়ারী ত্বরান্বিত করতে সূচী ব্যবহার করে। ফিল্টারিং ( WHERE ), বাছাই ( ORDER BY ), বা একটি কলামকে একত্রিত করার ( GROUP BY ) করার সময়, যদি টেবিলে কলামের জন্য একটি সূচক থাকে, প্রশ্নটি ত্বরান্বিত হয়।

আগের উদাহরণে, city অনুসারে ফিল্টার করার জন্য পুরো টেবিলটি স্ক্যান করা প্রয়োজন:

SELECT id, name
WHERE city = 'London, England';

অনেক শহরের প্রশ্ন সহ একটি অ্যাপের জন্য, আপনি একটি সূচী দিয়ে সেই প্রশ্নগুলিকে ত্বরান্বিত করতে পারেন:

CREATE INDEX city_index ON Customers(city);

একটি সূচক একটি অতিরিক্ত টেবিল হিসাবে প্রয়োগ করা হয়, সূচী কলাম দ্বারা বাছাই করা হয় এবং rowid এ ম্যাপ করা হয়:

শহর সারিবদ্ধ
গ্যারি, IN 2
লিভারপুল, ইংল্যান্ড 1
সেভিয়ার কাউন্টি, টিএন 3

মনে রাখবেন যে city কলামের স্টোরেজ খরচ এখন দ্বিগুণ, কারণ এটি এখন মূল টেবিল এবং সূচী উভয়েই উপস্থিত। যেহেতু আপনি সূচী ব্যবহার করছেন, যোগ করা সঞ্চয়স্থানের খরচ দ্রুত প্রশ্নের সুবিধার জন্য মূল্যবান। যাইহোক, এমন একটি সূচক বজায় রাখবেন না যা আপনি ব্যবহার করছেন না যাতে কোনো প্রশ্নের কর্মক্ষমতা লাভের জন্য স্টোরেজ খরচ পরিশোধ না করা যায়।

মাল্টি-কলাম ইনডেক্স তৈরি করুন

আপনার ক্যোয়ারী একাধিক কলাম একত্রিত হলে, আপনি ক্যোয়ারী সম্পূর্ণরূপে ত্বরান্বিত করতে বহু-কলাম সূচী তৈরি করতে পারেন। আপনি বাইরের কলামে একটি সূচী ব্যবহার করতে পারেন এবং ভিতরের অনুসন্ধানটি লিনিয়ার স্ক্যান হিসাবে করতে দিন।

উদাহরণস্বরূপ, নিম্নলিখিত ক্যোয়ারী দেওয়া:

SELECT id, name
WHERE city = 'London, England'
ORDER BY city, name

আপনি ক্যোয়ারীতে উল্লেখ করা একই ক্রমে একটি মাল্টি-কলাম সূচী দিয়ে ক্যোয়ারীকে ত্বরান্বিত করতে পারেন:

CREATE INDEX city_name_index ON Customers(city, name);

যাইহোক, যদি আপনার শুধুমাত্র city উপর একটি সূচক থাকে, তবে বাইরের অর্ডারিং এখনও ত্বরান্বিত হয়, যখন ভিতরের অর্ডারের জন্য একটি লিনিয়ার স্ক্যান প্রয়োজন।

এটি উপসর্গ অনুসন্ধানের সাথেও কাজ করে। উদাহরণস্বরূপ, ON Customers (city, name) এছাড়াও city অনুসারে ফিল্টারিং, অর্ডার এবং গ্রুপিংকে ত্বরান্বিত করে, যেহেতু একটি বহু-কলাম সূচকের জন্য সূচী সারণী প্রদত্ত ক্রম অনুসারে প্রদত্ত সূচী দ্বারা সাজানো হয়।

WITHOUT ROWID বিবেচনা করুন

ডিফল্টরূপে, SQLite আপনার টেবিলের জন্য একটি rowid কলাম তৈরি করে, যেখানে rowid হল একটি অন্তর্নিহিত INTEGER PRIMARY KEY AUTOINCREMENT । আপনার যদি ইতিমধ্যেই একটি কলাম থাকে যা INTEGER PRIMARY KEY , তাহলে এই কলামটি rowid এর একটি উপনাম হয়ে যায়।

INTEGER বা কলামের সংমিশ্রণ ছাড়া অন্য একটি প্রাথমিক কী আছে এমন টেবিলগুলির জন্য, WITHOUT ROWID বিবেচনা করুন।

BLOB হিসাবে ছোট ডেটা এবং ফাইল হিসাবে বড় ডেটা সংরক্ষণ করুন

আপনি যদি একটি সারির সাথে বড় ডেটা যুক্ত করতে চান, যেমন একটি ছবির থাম্বনেইল বা একটি পরিচিতির জন্য একটি ফটো, আপনি একটি BLOB কলামে বা একটি ফাইলে ডেটা সংরক্ষণ করতে পারেন এবং তারপর কলামে ফাইল পাথ সংরক্ষণ করতে পারেন৷

ফাইলগুলি সাধারণত 4 KB বৃদ্ধি পর্যন্ত বৃত্তাকার হয়৷ খুব ছোট ফাইলের জন্য, যেখানে রাউন্ডিং ত্রুটি তাৎপর্যপূর্ণ, সেগুলিকে BLOB হিসাবে ডাটাবেসে সংরক্ষণ করা আরও কার্যকর। SQLite ফাইলসিস্টেম কল কমিয়ে দেয় এবং কিছু ক্ষেত্রে অন্তর্নিহিত ফাইল সিস্টেমের চেয়ে দ্রুততর

ক্যোয়ারী কর্মক্ষমতা উন্নত করুন

প্রতিক্রিয়ার সময় কমিয়ে এবং প্রক্রিয়াকরণের দক্ষতা সর্বাধিক করে SQLite-এ ক্যোয়ারী কর্মক্ষমতা উন্নত করতে এই সেরা অনুশীলনগুলি অনুসরণ করুন।

শুধুমাত্র আপনার প্রয়োজন সারি পড়ুন

ফিল্টারগুলি আপনাকে নির্দিষ্ট মানদণ্ড যেমন তারিখের পরিসর, অবস্থান বা নাম উল্লেখ করে আপনার ফলাফলগুলিকে সংকুচিত করতে দেয়৷ সীমাগুলি আপনাকে ফলাফলের সংখ্যা নিয়ন্ত্রণ করতে দেয়:

কোটলিন

db.rawQuery("""
    SELECT name
    FROM Customers
    LIMIT 10;
    """.trimIndent(),
    null
).use { cursor ->
    while (cursor.moveToNext()) {
        ...
    }
}

জাভা

try (Cursor cursor = db.rawQuery("""
    SELECT name
    FROM Customers
    LIMIT 10;
    """, null)) {
  while (cursor.moveToNext()) {
    ...
  }
}

আপনার প্রয়োজন শুধুমাত্র কলাম পড়ুন

অপ্রয়োজনীয় কলাম নির্বাচন করা এড়িয়ে চলুন, যা আপনার প্রশ্নগুলিকে ধীর করে দিতে পারে এবং সম্পদের অপচয় করতে পারে। পরিবর্তে, শুধুমাত্র ব্যবহৃত কলাম নির্বাচন করুন।

নিম্নলিখিত উদাহরণে, আপনি id , name এবং phone নির্বাচন করুন:

কোটলিন

// This is not the most efficient way of doing this.
// See the following example for a better approach.

db.rawQuery(
    """
    SELECT id, name, phone
    FROM customers;
    """.trimIndent(),
    null
).use { cursor ->
    while (cursor.moveToNext()) {
        val name = cursor.getString(1)
        // ...
    }
}

জাভা

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT id, name, phone
    FROM customers;
    """, null)) {
  while (cursor.moveToNext()) {
    String name = cursor.getString(1);
    ...
  }
}

যাইহোক, আপনার শুধুমাত্র name কলাম প্রয়োজন:

কোটলিন

db.rawQuery("""
    SELECT name
    FROM Customers;
    """.trimIndent(),
    null
).use { cursor ->
    while (cursor.moveToNext()) {
        val name = cursor.getString(0)
        ...
    }
}

জাভা

try (Cursor cursor = db.rawQuery("""
    SELECT name
    FROM Customers;
    """, null)) {
  while (cursor.moveToNext()) {
    String name = cursor.getString(0);
    ...
  }
}

অনন্য মানগুলির জন্য DISTINCT ব্যবহার করুন৷

DISTINCT কীওয়ার্ড ব্যবহার করে প্রক্রিয়া করা প্রয়োজন এমন ডেটার পরিমাণ কমিয়ে আপনার প্রশ্নের কর্মক্ষমতা উন্নত করতে পারে। উদাহরণস্বরূপ, যদি আপনি একটি কলাম থেকে শুধুমাত্র অনন্য মান ফেরত দিতে চান, তাহলে DISTINCT ব্যবহার করুন:

কোটলিন

db.rawQuery("""
    SELECT DISTINCT name
    FROM Customers;
    """.trimIndent(),
    null
).use { cursor ->
    while (cursor.moveToNext()) {
        // Only iterate over distinct names in Kotlin
        ...
    }
}

জাভা

try (Cursor cursor = db.rawQuery("""
    SELECT DISTINCT name
    FROM Customers;
    """, null)) {
  while (cursor.moveToNext()) {
    // Only iterate over distinct names in Java
    ...
  }
}

যখনই সম্ভব সমষ্টিগত ফাংশন ব্যবহার করুন

সারি ডেটা ছাড়াই সমষ্টিগত ফলাফলের জন্য সমষ্টিগত ফাংশন ব্যবহার করুন। উদাহরণস্বরূপ, নিম্নোক্ত কোডটি অন্তত একটি মিলে যাওয়া সারি আছে কিনা তা পরীক্ষা করে:

কোটলিন

// This is not the most efficient way of doing this.
// See the following example for a better approach.

db.rawQuery("""
    SELECT id, name
    FROM Customers
    WHERE city = 'Paris';
    """.trimIndent(),
    null
).use { cursor ->
    if (cursor.moveToFirst()) {
        // At least one customer from Paris
        ...
    } else {
        // No customers from Paris
        ...
}

জাভা

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT id, name
    FROM Customers
    WHERE city = 'Paris';
    """, null)) {
  if (cursor.moveToFirst()) {
    // At least one customer from Paris
    ...
  } else {
    // No customers from Paris
    ...
  }
}

শুধুমাত্র প্রথম সারি আনতে, আপনি EXISTS() ব্যবহার করতে পারেন 0 ফেরত দিতে যদি একটি মিল সারি বিদ্যমান না থাকে এবং 1 যদি এক বা একাধিক সারি মেলে:

কোটলিন

db.rawQuery("""
    SELECT EXISTS (
        SELECT null
        FROM Customers
        WHERE city = 'Paris';
    );
    """.trimIndent(),
    null
).use { cursor ->
    if (cursor.moveToFirst() && cursor.getInt(0) == 1) {
        // At least one customer from Paris
        ...
    } else {
        // No customers from Paris
        ...
    }
}

জাভা

try (Cursor cursor = db.rawQuery("""
    SELECT EXISTS (
      SELECT null
      FROM Customers
      WHERE city = 'Paris'
    );
    """, null)) {
  if (cursor.moveToFirst() && cursor.getInt(0) == 1) {
    // At least one customer from Paris
    ...
  } else {
    // No customers from Paris
    ...
  }
}

আপনার অ্যাপ কোডে SQLite সমষ্টিগত ফাংশন ব্যবহার করুন:

  • COUNT : একটি কলামে কতগুলি সারি রয়েছে তা গণনা করে৷
  • SUM : একটি কলামে সমস্ত সংখ্যাসূচক মান যোগ করে।
  • MIN বা MAX : সর্বনিম্ন বা সর্বোচ্চ মান নির্ধারণ করে। সাংখ্যিক কলাম, DATE প্রকার এবং পাঠ্য প্রকারের জন্য কাজ করে।
  • AVG : গড় সংখ্যাসূচক মান খুঁজে বের করে।
  • GROUP_CONCAT : একটি ঐচ্ছিক বিভাজক সহ স্ট্রিংগুলিকে সংযুক্ত করে৷

Cursor.getCount() এর পরিবর্তে COUNT() ব্যবহার করুন

নিম্নলিখিত উদাহরণে, Cursor.getCount() ফাংশন ডাটাবেস থেকে সমস্ত সারি পড়ে এবং সমস্ত সারি মান প্রদান করে:

কোটলিন

// This is not the most efficient way of doing this.
// See the following example for a better approach.

db.rawQuery("""
    SELECT id
    FROM Customers;
    """.trimIndent(),
    null
).use { cursor ->
    val count = cursor.getCount()
}

জাভা

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT id
    FROM Customers;
    """, null)) {
  int count = cursor.getCount();
  ...
}

যাইহোক, COUNT() ব্যবহার করে, ডাটাবেস শুধুমাত্র গণনা প্রদান করে:

কোটলিন

db.rawQuery("""
    SELECT COUNT(*)
    FROM Customers;
    """.trimIndent(),
    null
).use { cursor ->
    cursor.moveToFirst()
    val count = cursor.getInt(0)
}

জাভা

try (Cursor cursor = db.rawQuery("""
    SELECT COUNT(*)
    FROM Customers;
    """, null)) {
  cursor.moveToFirst();
  int count = cursor.getInt(0);
  ...
}

কোডের পরিবর্তে নেস্ট কোয়েরি

এসকিউএল কম্পোজযোগ্য এবং সাবকোয়ারি, যোগদান এবং বিদেশী কী সীমাবদ্ধতা সমর্থন করে। আপনি অ্যাপ কোডের মধ্য দিয়ে না গিয়ে একটি প্রশ্নের ফলাফল অন্য কোয়েরিতে ব্যবহার করতে পারেন। এটি SQLite থেকে ডেটা অনুলিপি করার প্রয়োজনীয়তা হ্রাস করে এবং ডাটাবেস ইঞ্জিনকে আপনার ক্যোয়ারী অপ্টিমাইজ করতে দেয়।

নিম্নলিখিত উদাহরণে, কোন শহরে সবচেয়ে বেশি গ্রাহক রয়েছে তা খুঁজে বের করতে আপনি একটি ক্যোয়ারী চালাতে পারেন, তারপর সেই শহরের সমস্ত গ্রাহকদের খুঁজে পেতে অন্য কোয়েরিতে ফলাফলটি ব্যবহার করুন:

কোটলিন

// This is not the most efficient way of doing this.
// See the following example for a better approach.

db.rawQuery("""
    SELECT city
    FROM Customers
    GROUP BY city
    ORDER BY COUNT(*) DESC
    LIMIT 1;
    """.trimIndent(),
    null
).use { cursor ->
    if (cursor.moveToFirst()) {
        val topCity = cursor.getString(0)
        db.rawQuery("""
            SELECT name, city
            FROM Customers
            WHERE city = ?;
        """.trimIndent(),
        arrayOf(topCity)).use { innerCursor ->
            while (innerCursor.moveToNext()) {
                ...
            }
        }
    }
}

জাভা

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT city
    FROM Customers
    GROUP BY city
    ORDER BY COUNT(*) DESC
    LIMIT 1;
    """, null)) {
  if (cursor.moveToFirst()) {
    String topCity = cursor.getString(0);
    try (Cursor innerCursor = db.rawQuery("""
        SELECT name, city
        FROM Customers
        WHERE city = ?;
        """, new String[] {topCity})) {
        while (innerCursor.moveToNext()) {
          ...
        }
    }
  }
}

পূর্ববর্তী উদাহরণের অর্ধেক সময়ের মধ্যে ফলাফল পেতে, নেস্টেড বিবৃতি সহ একটি একক SQL ক্যোয়ারী ব্যবহার করুন:

কোটলিন

db.rawQuery("""
    SELECT name, city
    FROM Customers
    WHERE city IN (
        SELECT city
        FROM Customers
        GROUP BY city
        ORDER BY COUNT (*) DESC
        LIMIT 1;
    );
    """.trimIndent(),
    null
).use { cursor ->
    if (cursor.moveToNext()) {
        ...
    }
}

জাভা

try (Cursor cursor = db.rawQuery("""
    SELECT name, city
    FROM Customers
    WHERE city IN (
      SELECT city
      FROM Customers
      GROUP BY city
      ORDER BY COUNT(*) DESC
      LIMIT 1
    );
    """, null)) {
  while(cursor.moveToNext()) {
    ...
  }
}

এসকিউএল-এ স্বতন্ত্রতা পরীক্ষা করুন

যদি একটি সারি সন্নিবেশ করা উচিত নয় যদি না একটি নির্দিষ্ট কলাম মান সারণিতে অনন্য হয়, তাহলে কলামের সীমাবদ্ধতা হিসাবে সেই স্বতন্ত্রতা প্রয়োগ করা আরও কার্যকর হতে পারে।

নিম্নলিখিত উদাহরণে, একটি ক্যোয়ারী ঢোকানো সারিটি যাচাই করতে এবং অন্যটি আসলে সন্নিবেশ করার জন্য চালানো হয়:

কোটলিন

// This is not the most efficient way of doing this.
// See the following example for a better approach.

db.rawQuery(
    """
    SELECT EXISTS (
        SELECT null
        FROM customers
        WHERE username = ?
    );
    """.trimIndent(),
    arrayOf(customer.username)
).use { cursor ->
    if (cursor.moveToFirst() && cursor.getInt(0) == 1) {
        throw AddCustomerException(customer)
    }
}
db.execSQL(
    "INSERT INTO customers VALUES (?, ?, ?)",
    arrayOf(
        customer.id.toString(),
        customer.name,
        customer.username
    )
)

জাভা

// This is not the most efficient way of doing this.
// See the following example for a better approach.

try (Cursor cursor = db.rawQuery("""
    SELECT EXISTS (
      SELECT null
      FROM customers
      WHERE username = ?
    );
    """, new String[] { customer.username })) {
  if (cursor.moveToFirst() && cursor.getInt(0) == 1) {
    throw new AddCustomerException(customer);
  }
}
db.execSQL(
    "INSERT INTO customers VALUES (?, ?, ?)",
    new String[] {
      String.valueOf(customer.id),
      customer.name,
      customer.username,
    });

কোটলিন বা জাভাতে অনন্য সীমাবদ্ধতা পরীক্ষা করার পরিবর্তে, আপনি যখন টেবিলটি সংজ্ঞায়িত করবেন তখন আপনি এটি SQL এ পরীক্ষা করতে পারেন:

CREATE TABLE Customers(
  id INTEGER PRIMARY KEY,
  name TEXT,
  username TEXT UNIQUE
);

SQLite নিম্নলিখিত হিসাবে একই কাজ করে:

CREATE TABLE Customers(...);
CREATE UNIQUE INDEX CustomersUsername ON Customers(username);

এখন আপনি একটি সারি সন্নিবেশ করতে পারেন এবং SQLite-কে সীমাবদ্ধতা পরীক্ষা করতে দিন:

কোটলিন

try {
    db.execSql(
        "INSERT INTO Customers VALUES (?, ?, ?)",
        arrayOf(customer.id.toString(), customer.name, customer.username)
    )
} catch(e: SQLiteConstraintException) {
    throw AddCustomerException(customer, e)
}

জাভা

try {
  db.execSQL(
      "INSERT INTO Customers VALUES (?, ?, ?)",
      new String[] {
        String.valueOf(customer.id),
        customer.name,
        customer.username,
      });
} catch (SQLiteConstraintException e) {
  throw new AddCustomerException(customer, e);
}

SQLite একাধিক কলাম সহ অনন্য সূচী সমর্থন করে:

CREATE TABLE table(...);
CREATE UNIQUE INDEX unique_table ON table(column1, column2, ...);

SQLite কোটলিন বা জাভা কোডের চেয়ে দ্রুত এবং কম ওভারহেড সহ সীমাবদ্ধতা যাচাই করে। অ্যাপ কোডের পরিবর্তে SQLite ব্যবহার করা একটি সর্বোত্তম অনুশীলন।

একটি একক লেনদেনে একাধিক সন্নিবেশ ব্যাচ করুন

একটি লেনদেন একাধিক ক্রিয়াকলাপের প্রতিশ্রুতি দেয়, যা কেবল দক্ষতাই নয় বরং সঠিকতাও উন্নত করে। ডেটা সামঞ্জস্য উন্নত করতে এবং কর্মক্ষমতা ত্বরান্বিত করতে, আপনি ব্যাচ সন্নিবেশ করতে পারেন:

কোটলিন

db.beginTransaction()
try {
    customers.forEach { customer ->
        db.execSql(
            "INSERT INTO Customers VALUES (?, ?, ...)",
            arrayOf(customer.id.toString(), customer.name, ...)
        )
    }
} finally {
    db.endTransaction()
}

জাভা

db.beginTransaction();
try {
  for (customer : Customers) {
    db.execSQL(
        "INSERT INTO Customers VALUES (?, ?, ...)",
        new String[] {
          String.valueOf(customer.id),
          customer.name,
          ...
        });
  }
} finally {
  db.endTransaction()
}

সমস্যা সমাধানের সরঞ্জাম ব্যবহার করুন

SQLite কর্মক্ষমতা পরিমাপ করতে সাহায্য করার জন্য নিম্নলিখিত সমস্যা সমাধানের সরঞ্জাম সরবরাহ করে।

SQLite এর ইন্টারেক্টিভ প্রম্পট ব্যবহার করুন

প্রশ্নগুলি চালানো এবং শিখতে আপনার মেশিনে SQLite চালান। বিভিন্ন Android প্ল্যাটফর্ম সংস্করণ SQLite এর বিভিন্ন সংশোধন ব্যবহার করে। Android-চালিত ডিভাইসে একই ইঞ্জিন ব্যবহার করতে, adb shell ব্যবহার করুন এবং আপনার টার্গেট ডিভাইসে sqlite3 চালান।

আপনি SQLite-কে সময়ের প্রশ্ন জিজ্ঞাসা করতে পারেন:

sqlite> .timer on
sqlite> SELECT ...
Run Time: real ... user ... sys ...

EXPLAIN QUERY PLAN

EXPLAIN QUERY PLAN ব্যবহার করে আপনি SQLite-কে জিজ্ঞাসা করতে পারেন যে এটি কীভাবে একটি প্রশ্নের উত্তর দিতে চায়:

sqlite> EXPLAIN QUERY PLAN
SELECT id, name
FROM Customers
WHERE city = 'Paris';
QUERY PLAN
`--SCAN Customers

পূর্ববর্তী উদাহরণে প্যারিস থেকে সমস্ত গ্রাহকদের খুঁজে বের করার জন্য একটি সূচক ছাড়াই একটি সম্পূর্ণ টেবিল স্ক্যান প্রয়োজন। একে রৈখিক জটিলতা বলা হয়। SQLite-এর সমস্ত সারি পড়তে হবে এবং শুধুমাত্র প্যারিসের গ্রাহকদের সাথে মেলে এমন সারিগুলি রাখতে হবে। এটি ঠিক করতে, আপনি একটি সূচক যোগ করতে পারেন:

sqlite> CREATE INDEX Idx1 ON Customers(city);
sqlite> EXPLAIN QUERY PLAN
SELECT id, name
FROM Customers
WHERE city = 'Paris';
QUERY PLAN
`--SEARCH test USING INDEX Idx1 (city=?

আপনি যদি ইন্টারেক্টিভ শেল ব্যবহার করেন তবে আপনি SQLite কে সর্বদা ক্যোয়ারী পরিকল্পনা ব্যাখ্যা করতে বলতে পারেন:

sqlite> .eqp on

আরও তথ্যের জন্য, ক্যোয়ারী প্ল্যানিং দেখুন।

SQLite বিশ্লেষক

SQLite অতিরিক্ত তথ্য ডাম্প করার জন্য sqlite3_analyzer কমান্ড-লাইন ইন্টারফেস (CLI) অফার করে যা কর্মক্ষমতা সমস্যা সমাধানের জন্য ব্যবহার করা যেতে পারে। ইনস্টল করতে, SQLite ডাউনলোড পৃষ্ঠায় যান।

আপনি বিশ্লেষণের জন্য একটি টার্গেট ডিভাইস থেকে আপনার ওয়ার্কস্টেশনে একটি ডাটাবেস ফাইল ডাউনলোড করতে adb pull ব্যবহার করতে পারেন:

adb pull /data/data/<app_package_name>/databases/<db_name>.db

SQLite ব্রাউজার

এছাড়াও আপনি SQLite ডাউনলোড পৃষ্ঠায় GUI টুল SQLite ব্রাউজার ইনস্টল করতে পারেন।

অ্যান্ড্রয়েড লগিং

অ্যান্ড্রয়েড টাইমস SQLite প্রশ্ন করে এবং সেগুলিকে আপনার জন্য লগ করে:

# Enable query time logging
$ adb shell setprop log.tag.SQLiteTime VERBOSE
# Disable query time logging
$ adb shell setprop log.tag.SQLiteTime ERROR
```### Perfetto tracing

### Perfetto tracing {:#perfetto-tracing}

When [configuring Perfetto](https://perfetto.dev/docs/concepts/config), you may
add the following to include tracks for individual queries:

```protobuf
data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      atrace_categories: "database"
    }
  }
}
{% verbatim %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}