ভূমিকা
এটি SQL ইন্টারভিউ প্রস্তুতির দ্বিতীয় পর্ব। এখানে আরও ১০টি গুরুত্বপূর্ণ SQL প্রশ্ন এবং বিস্তারিত উত্তর বাংলায় দেওয়া হয়েছে। এগুলো বিশেষভাবে senior-level Java developer ইন্টারভিউর জন্য প্রাসঙ্গিক।
১১. CTE (Common Table Expression) কী এবং কেন ব্যবহার করবেন?
উত্তর:
CTE হলো একটি named temporary result set যা WITH keyword দিয়ে তৈরি করা হয় এবং শুধুমাত্র সেই query-র মধ্যে ব্যবহারযোগ্য। এটি complex query-কে ছোট, পাঠযোগ্য অংশে ভাগ করতে সাহায্য করে।
CTE কেন ব্যবহার করবেন:
- Code পাঠযোগ্যতা বাড়ায়
- একই subquery বারবার লেখা এড়ানো যায়
- Recursive query লেখা সম্ভব হয়
- Debugging সহজ হয়
-- সাধারণ CTE উদাহরণ
WITH high_earners AS (
SELECT emp_id, name, salary, dept_id
FROM employees
WHERE salary > 70000
),
dept_summary AS (
SELECT dept_id, COUNT(*) AS high_earner_count, AVG(salary) AS avg_salary
FROM high_earners
GROUP BY dept_id
)
SELECT d.dept_name, ds.high_earner_count, ds.avg_salary
FROM dept_summary ds
JOIN departments d ON ds.dept_id = d.dept_id
ORDER BY ds.avg_salary DESC;
CTE বনাম Subquery:
- CTE একবার define করে একাধিক জায়গায় reference করা যায়
- Subquery প্রতিবার inline লিখতে হয়
- CTE recursive হতে পারে, subquery পারে না
১২. SQL-এ View কী? View ব্যবহারের সুবিধা ও সীমাবদ্ধতা কী?
উত্তর:
View হলো একটি virtual table যা একটি SQL query-র উপর ভিত্তি করে তৈরি। এটি নিজে কোনো ডেটা store করে না, বরং query execute করার সময় data retrieve করে।
সুবিধা:
- জটিল query পুনরায় ব্যবহারযোগ্য করে
- Data security নিশ্চিত করে (sensitive column লুকানো যায়)
- Business logic এক জায়গায় রাখা যায়
- Backward compatibility বজায় রাখতে সাহায্য করে
সীমাবদ্ধতা:
- Performance: প্রতিবার query execute করে (Materialized View ব্যতীত)
- Updatable view-এ সীমাবদ্ধতা থাকে
- Complex view debug করা কঠিন
-- View তৈরি
CREATE VIEW employee_details AS
SELECT
e.emp_id,
e.name,
e.salary,
d.dept_name,
m.name AS manager_name
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
LEFT JOIN employees m ON e.manager_id = m.emp_id;
-- View ব্যবহার (সাধারণ টেবিলের মতো)
SELECT * FROM employee_details WHERE dept_name = 'Engineering';
-- View update (simple view-এ কাজ করে)
UPDATE employee_details SET salary = 80000 WHERE emp_id = 101;
-- View মুছে ফেলা
DROP VIEW employee_details;
১৩. SQL-এ Trigger কী এবং কখন ব্যবহার করবেন?
উত্তর:
Trigger হলো একটি stored procedure যা automatically execute হয় যখন কোনো নির্দিষ্ট event (INSERT, UPDATE, DELETE) ঘটে।
Trigger-এর ধরন:
- BEFORE Trigger: Operation-এর আগে execute হয়
- AFTER Trigger: Operation-এর পরে execute হয়
- INSTEAD OF Trigger: View-এ operation-এর পরিবর্তে execute হয়
-- BEFORE INSERT Trigger: created_at স্বয়ংক্রিয়ভাবে set করা
CREATE TRIGGER set_created_at
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
SET NEW.created_at = NOW();
SET NEW.updated_at = NOW();
END;
-- AFTER UPDATE Trigger: Audit log রাখা
CREATE TABLE salary_audit (
audit_id INT AUTO_INCREMENT PRIMARY KEY,
emp_id INT,
old_salary DECIMAL(10,2),
new_salary DECIMAL(10,2),
changed_at DATETIME,
changed_by VARCHAR(100)
);
CREATE TRIGGER log_salary_change
AFTER UPDATE ON employees
FOR EACH ROW
BEGIN
IF OLD.salary != NEW.salary THEN
INSERT INTO salary_audit (emp_id, old_salary, new_salary, changed_at, changed_by)
VALUES (NEW.emp_id, OLD.salary, NEW.salary, NOW(), USER());
END IF;
END;
কখন Trigger ব্যবহার করবেন: Audit log, data validation, automatic timestamp, business rules enforce করতে।
১৪. SQL-এ Isolation Levels কী কী এবং কোনটি কখন ব্যবহার করবেন?
উত্তর:
Isolation Level নির্ধারণ করে যে concurrent transactions একে অপরের উপর কতটা প্রভাব ফেলতে পারবে।
চারটি Isolation Level (কম থেকে বেশি isolation):
| Isolation Level | Dirty Read | Non-Repeatable Read | Phantom Read |
|---|---|---|---|
| READ UNCOMMITTED | সম্ভব | সম্ভব | সম্ভব |
| READ COMMITTED | নেই | সম্ভব | সম্ভব |
| REPEATABLE READ | নেই | নেই | সম্ভব |
| SERIALIZABLE | নেই | নেই | নেই |
সমস্যাগুলোর সংজ্ঞা:
- Dirty Read: Commit না হওয়া data read করা
- Non-Repeatable Read: একই transaction-এ একই row দুবার read করলে ভিন্ন result
- Phantom Read: একই transaction-এ একই query দুবার চালালে ভিন্ন row set
-- Isolation level set করা (MySQL)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT * FROM accounts WHERE id = 1;
COMMIT;
-- Spring/Java-তে
-- @Transactional(isolation = Isolation.READ_COMMITTED)
ব্যবহারিক পরামর্শ: বেশিরভাগ ক্ষেত্রে READ COMMITTED যথেষ্ট। Financial transactions-এ SERIALIZABLE ব্যবহার করুন তবে performance cost মাথায় রাখুন।
১৫. SQL-এ EXISTS বনাম IN — কোনটি কখন ব্যবহার করবেন?
উত্তর:
IN: একটি static value list বা subquery-র result-এর সাথে match করে।
EXISTS: Subquery কোনো row return করে কিনা শুধু সেটা check করে (TRUE/FALSE)।
-- IN উদাহরণ
SELECT name FROM employees
WHERE dept_id IN (1, 3, 5);
-- IN with subquery
SELECT name FROM employees
WHERE dept_id IN (
SELECT dept_id FROM departments WHERE location = 'Dhaka'
);
-- EXISTS উদাহরণ (বেশি efficient বড় dataset-এ)
SELECT name FROM employees e
WHERE EXISTS (
SELECT 1 FROM departments d
WHERE d.dept_id = e.dept_id
AND d.location = 'Dhaka'
);
-- NOT EXISTS vs NOT IN পার্থক্য
-- NOT IN: subquery-তে NULL থাকলে সব row বাদ পড়ে!
SELECT name FROM employees
WHERE dept_id NOT IN (SELECT dept_id FROM departments WHERE location IS NULL);
-- ↑ এটি কোনো result নাও দিতে পারে যদি NULL থাকে
-- NOT EXISTS: NULL-safe
SELECT name FROM employees e
WHERE NOT EXISTS (
SELECT 1 FROM departments d
WHERE d.dept_id = e.dept_id AND d.location IS NULL
);
কখন কোনটি:
- IN ভালো: ছোট static list বা ছোট subquery
- EXISTS ভালো: বড় টেবিল, correlated subquery, NULL থাকতে পারে
১৬. Database Sharding এবং Partitioning-এর মধ্যে পার্থক্য কী?
উত্তর:
Partitioning হলো একটি টেবিলকে ভৌতিকভাবে একই database-এ একাধিক ভাগে ভাগ করা। Logical একটি টেবিল কিন্তু internally আলাদা partition-এ data store হয়।
Sharding হলো data একাধিক আলাদা database server-এ ভাগ করা। প্রতিটি shard একটি স্বাধীন database।
-- MySQL Table Partitioning উদাহরণ
CREATE TABLE orders (
order_id INT NOT NULL,
order_date DATE NOT NULL,
amount DECIMAL(10,2),
customer_id INT
)
PARTITION BY RANGE (YEAR(order_date)) (
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
-- Partition pruning: শুধু ২০২৩ সালের data query
SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31';
-- MySQL স্বয়ংক্রিয়ভাবে শুধু p2023 partition scan করবে
-- Partition info দেখা
SELECT PARTITION_NAME, TABLE_ROWS
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'orders';
Partitioning-এর ধরন:
- RANGE: Date/number range অনুযায়ী
- LIST: নির্দিষ্ট value-এর list অনুযায়ী
- HASH: Hash function ব্যবহার করে সমানভাবে
- KEY: Column value-এর key অনুযায়ী
১৭. SQL-এ GROUP BY ROLLUP এবং CUBE কী?
উত্তর:
ROLLUP subtotal এবং grand total সহ hierarchical summary তৈরি করে।
CUBE সব সম্ভাব্য combination-এর subtotal তৈরি করে।
-- Sample data: sales by year, region, product
-- ROLLUP উদাহরণ: region এবং year-এর subtotal
SELECT
COALESCE(region, 'সব অঞ্চল') AS অঞ্চল,
COALESCE(CAST(year AS CHAR), 'সব বছর') AS বছর,
SUM(sales_amount) AS মোট_বিক্রয়
FROM sales
GROUP BY region, year WITH ROLLUP;
-- ফলাফল উদাহরণ:
-- Dhaka | 2023 | 500000
-- Dhaka | 2024 | 620000
-- Dhaka | সব বছর | 1120000 ← subtotal for Dhaka
-- Chittagong | 2023 | 300000
-- Chittagong | সব বছর | 300000
-- সব অঞ্চল | সব বছর | 1420000 ← grand total
-- CUBE উদাহরণ (সব combination)
SELECT
COALESCE(region, 'সব') AS অঞ্চল,
COALESCE(product, 'সব') AS পণ্য,
COALESCE(CAST(year AS CHAR), 'সব') AS বছর,
SUM(sales_amount) AS মোট
FROM sales
GROUP BY region, product, year WITH CUBE;
-- CUBE সব সম্ভাব্য combination-এর জন্য subtotal দেয়
ব্যবহার: BI (Business Intelligence) dashboard, reporting query-তে ROLLUP/CUBE অত্যন্ত কার্যকর।
১৮. SQL-এ Full-Text Search কীভাবে কাজ করে?
উত্তর:
Full-Text Search হলো text data-র মধ্যে keyword search করার একটি বিশেষ mechanism যা LIKE '%keyword%' এর চেয়ে অনেক বেশি efficient।
-- Full-Text Index তৈরি
CREATE TABLE articles (
article_id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255),
content TEXT,
FULLTEXT idx_search (title, content)
);
-- Natural Language Mode (default)
SELECT article_id, title,
MATCH(title, content) AGAINST ('Java SQL optimization') AS relevance_score
FROM articles
WHERE MATCH(title, content) AGAINST ('Java SQL optimization')
ORDER BY relevance_score DESC;
-- Boolean Mode: advanced search
SELECT title
FROM articles
WHERE MATCH(title, content) AGAINST (
'+Java +SQL -Python' -- Java এবং SQL থাকতে হবে, Python থাকলে বাদ
IN BOOLEAN MODE
);
-- Phrase search
SELECT title
FROM articles
WHERE MATCH(title, content) AGAINST (
'"database optimization"' -- exact phrase
IN BOOLEAN MODE
);
LIKE বনাম FULLTEXT:
LIKE '%keyword%'index ব্যবহার করে না, slowFULLTEXTinverted index ব্যবহার করে, fast এবং relevance scoring দেয়- বড় text data-তে সবসময় FULLTEXT ব্যবহার করুন
১৯. SQL-এ Materialized View কী এবং Regular View-এর সাথে পার্থক্য কী?
উত্তর:
Regular View কোনো data store করে না — query করলে প্রতিবার underlying টেবিল থেকে data নিয়ে আসে।
Materialized View query-র result physically store করে রাখে। নির্দিষ্ট সময় পরপর বা manually refresh করতে হয়।
-- PostgreSQL-এ Materialized View
CREATE MATERIALIZED VIEW monthly_sales_summary AS
SELECT
DATE_TRUNC('month', order_date) AS month,
customer_id,
COUNT(order_id) AS order_count,
SUM(total_amount) AS total_spent
FROM orders
WHERE status = 'completed'
GROUP BY DATE_TRUNC('month', order_date), customer_id
WITH DATA; -- এখনই populate করো
-- Index on Materialized View
CREATE INDEX idx_mv_month ON monthly_sales_summary(month);
CREATE INDEX idx_mv_customer ON monthly_sales_summary(customer_id);
-- Manual Refresh
REFRESH MATERIALIZED VIEW monthly_sales_summary;
-- Concurrent Refresh (lock ছাড়া, unique index দরকার)
REFRESH MATERIALIZED VIEW CONCURRENTLY monthly_sales_summary;
MySQL-এ Materialized View নেই, তাই সেখানে সাধারণত:
- Summary টেবিল তৈরি করে Event Scheduler দিয়ে নিয়মিত populate করা হয়
- অথবা application layer থেকে cache maintain করা হয়
কখন ব্যবহার করবেন: ভারী aggregation query যা বারবার চালাতে হয় কিন্তু real-time data দরকার নেই।
২০. SQL Performance Tuning-এ Execution Plan কীভাবে পড়বেন?
উত্তর:
EXPLAIN বা EXPLAIN ANALYZE command দিয়ে query-র execution plan দেখা যায় — database engine কীভাবে query execute করবে সেটা জানা যায়।
-- MySQL EXPLAIN
EXPLAIN SELECT e.name, d.dept_name
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
WHERE e.salary > 50000;
-- বিস্তারিত জানতে EXPLAIN ANALYZE (MySQL 8.0+)
EXPLAIN ANALYZE
SELECT e.name, d.dept_name, AVG(e.salary) OVER (PARTITION BY e.dept_id)
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
WHERE e.salary > 50000;
EXPLAIN Output-এর গুরুত্বপূর্ণ কলাম:
| কলাম | অর্থ | ভালো/খারাপ |
|---|---|---|
| type | Join type | system > const > eq_ref > ref > range > index > ALL |
| key | ব্যবহৃত index | NULL হলে index নেই |
| rows | আনুমানিক scan করা rows | কম হলে ভালো |
| Extra | অতিরিক্ত তথ্য | "Using filesort" বা "Using temporary" খারাপ |
-- সমস্যা চিহ্নিতকরণ ও সমাধান
-- ১. Full Table Scan (type = ALL) — খারাপ
EXPLAIN SELECT * FROM employees WHERE UPPER(name) = 'JOHN';
-- সমাধান: function ছাড়া index-friendly লিখুন
SELECT * FROM employees WHERE name = 'John';
-- ২. Filesort — ধীর
EXPLAIN SELECT * FROM employees ORDER BY salary DESC;
-- সমাধান: salary-তে index যোগ করুন
CREATE INDEX idx_salary ON employees(salary);
-- ৩. Using temporary — খারাপ
EXPLAIN SELECT dept_id, COUNT(*) FROM employees GROUP BY dept_id;
-- সমাধান: dept_id-এ index থাকলে temporary table দরকার হয় না
Performance Checklist:
type = ALLদেখলে index যোগ করুনExtra = Using filesortদেখলে ORDER BY column-এ index দিনrowsসংখ্যা বেশি হলে WHERE clause review করুন- JOIN column-গুলোতে index আছে কিনা যাচাই করুন
উপসংহার
এই দ্বিতীয় পর্বে আমরা আরও advanced SQL বিষয়গুলো দেখলাম:
- CTE: জটিল query সহজ ও পাঠযোগ্য করে
- View ও Trigger: Database-level business logic
- Isolation Level: Concurrency সমস্যা সমাধান
- Partitioning: বড় টেবিলের performance উন্নয়ন
- EXPLAIN: Query bottleneck চিহ্নিতকরণ
Senior Java developer হিসেবে শুধু query লেখা নয়, কেন এবং কীভাবে optimize করতে হয় সেটা বোঝাটা ইন্টারভিউতে আপনাকে আলাদা করবে।