🚀 “The query was taking 45 minutes… we reduced it to 12 seconds.” Last week, I worked on a performance issue in both Microsoft SQL Server and PostgreSQL — same business problem, different engines. Here’s what I learned 👇 🔍 Problem A reporting query: Multiple joins (5+ tables) Huge data (~50M rows) Running during peak hours Blocking other critical transactions ⚠️ What was going wrong? In SQL Server: Parallelism overhead (CXPACKET / CXCONSUMER waits) Missing indexes Bad execution plan due to outdated statistics In PostgreSQL: Sequential scan instead of index scan Poor query plan due to wrong cost estimation No proper vacuum/analyze 🛠️ What we did (Real Fix) ✅ 1. Index Optimization Added covering indexes (SQL Server) Created composite indexes (PostgreSQL) 👉 Result: Massive reduction in I/O ✅ 2. Updated Statistics SQL Server → UPDATE STATISTICS PostgreSQL → ANALYZE 👉 Better execution plans instantly ✅ 3. Query Rewrite Removed unnecessary columns Reduced joins Used EXISTS instead of IN 👉 Cleaner + faster execution ✅ 4. Parallelism Control (SQL Server) Tuned MAXDOP Adjusted cost threshold 👉 Reduced CPU pressure ✅ 5. Vacuum & Maintenance (PostgreSQL) Ran VACUUM ANALYZE Checked bloat 👉 Improved planner accuracy 📈 Final Result 🔥 Execution time: 45 minutes → 12 seconds 🔥 CPU usage dropped by 70% 🔥 Blocking issues eliminated 💡 Key Takeaway Performance tuning is NOT about one fix. It’s about: Understanding execution plans Knowing how the engine behaves Fixing root causes, not symptoms. #SQLServer #PostgreSQL #PerformanceTuning #Database #DBA #QueryOptimization #TechLeadership #DataEngineering
Reducing SQL Query Time from 45 Minutes to 12 Seconds
More Relevant Posts
-
🔍 LEN vs LENGTH in SQL — Small Difference, Big Impact! When working with SQL, even seemingly small functions can make a significant difference in your results. One such commonly confused pair is LEN() and LENGTH(). Let’s break it down 👇 📌 LEN() Primarily used in SQL Server Returns the number of characters in a string ⚠️ Excludes trailing spaces 👉 Example: LEN('Data ') → 4 📌 LENGTH() Common in MySQL, PostgreSQL, Oracle Returns the number of characters in a string ✅ Includes trailing spaces 👉 Example: LENGTH('Data ') → 5 💡 Key Takeaway Choosing the wrong function can lead to unexpected results, especially when dealing with data validation, cleaning, or reporting. 🎯 Pro Tip: Always be aware of the SQL dialect you're working with—functions may behave differently across systems! 💬 Have you ever faced issues due to trailing spaces in SQL? Share your experience below! #SQL #DataAnalytics #DatabaseManagement #SQLServer #MySQL #LearningSQL #TechTips #DataEngineering #Coding #LinkedInLearning
To view or add a comment, sign in
-
📌Why SQL Indexing Matters An SQL index is typically implemented using data structures like B-Trees (default in many databases) that allow the database to locate rows efficiently without scanning the full table. Suppose you frequently run: SELECT * FROM users WHERE email = 'abc@example.com'; Without an index → the database performs a full table scan (O(n)) Create an index: CREATE INDEX idx_users_email ON users(email); With the index, the database can traverse the B-Tree and find matching rows much faster (O(log n)) ✅ Faster filtering on WHERE clauses ✅ Better performance for joins ✅ Can optimize ORDER BY/ GROUP BY ✅ Critical for scaling read-heavy applications There are some tradeoffs as well like extra storage usage and slower writes because indexes must also be updated when we insert , update or delete. Use indexing for high-read and low-write columns, foreign keys or column joins and for frequently filtered or sorted fields. Do not index every column blindly. The best index is not “more indexes” it’s the right indexes for your query patterns. #SQL #DatabaseOptimization #BackendDevelopment #SystemDesign #PostgreSQL #MySQL #SoftwareEngineering
To view or add a comment, sign in
-
-
Most engineers think table partitioning is an "enterprise" feature. In reality, it's often the simplest fix for your slow time-series queries. If you’re logging events or anything time-based in PostgreSQL and everything lives in one giant table, you’re forcing every query to fight through data it doesn’t care about. Even with indexes. In the example from the video, the base table is `events` with: - `id` (generated) - `created_at` (timestamp) - `user_id` - `event_id` The only difference from a normal table definition is this line: ```sql PARTITION BY RANGE (created_at) ``` From there, you create monthly partitions: ```sql CREATE TABLE events_2024_01 PARTITION OF events FOR VALUES FROM ('2024-01-01') TO ('2024-02-01'); CREATE TABLE events_2024_02 PARTITION OF events FOR VALUES FROM ('2024-02-01') TO ('2024-03-01'); ``` When you insert 20,000+ rows per month and query with a `WHERE created_at BETWEEN ...`, PostgreSQL can do partition pruning: it only touches the relevant child tables instead of scanning the entire dataset. The key takeaway: if your queries are almost always time-bounded, a properly partitioned table can give you a bigger win than another round of index tweaking. I walk through the exact SQL and show how partition pruning changes what PostgreSQL actually scans here: https://lnkd.in/ekhNRkss
To view or add a comment, sign in
-
Ever wondered what happens when a SQL query runs? Let me tell you . That “simple” SELECT isn’t simple at all. SELECT * FROM users WHERE id = 17; Looks straightforward. Under the hood in PostgreSQL, it’s a four-stage decision engine. *1. Parse* PostgreSQL breaks your SQL into an internal structure, validates syntax, and resolves table and column names. Get this wrong and the query never runs. *2. Rewrite* Before execution, PostgreSQL applies rules and view transformations. Your query might already be reshaped before the planner even sees it. *3. Plan* This is where PostgreSQL earns its reputation. It weighs multiple execution paths: Index Scan, Sequential Scan, Bitmap Heap Scan. It picks the “cheapest” option based on table stats, row estimates, and data distribution. Cheapest ≠ fastest. It’s just what the model predicts will cost least in I/O and CPU. *4. Execute with MVCC* Now it finally touches data. But it also checks visibility. A row can exist on disk and still be invisible to you if your transaction shouldn’t see it yet. That’s MVCC in action. *The part most engineers overlook:* This entire flow happens for every SELECT. Every time. So when performance tanks, it’s usually not the query. It’s the context: - Outdated statistics → wrong plan - Poor indexing → wrong scan - Skewed data → bad estimates PostgreSQL isn’t just executing your query. It’s deciding _how_ to execute it. And that decision determines whether your query runs in milliseconds or minutes. What’s the most surprising query plan you’ve seen in production? #PostgreSQL #Databases #Performance #QueryTuning
To view or add a comment, sign in
-
Index in GROUP BY Clause in SQL Server In this post, I’ll explain how indexes improve performance in a GROUP BY query and also touch on the concept of a covering query. SQL Server uses two main algorithms for grouping data: Hash Aggregate – Creates a temporary hash table to store grouped results. Sort + Group – Sorts data by grouping columns, then aggregates sequentially. Both approaches require intermediate processing, but the Sort + Group algorithm can leverage indexes to avoid sorting, improving performance. 🔹 Why Index Matters in GROUP BY Consider this query: SELECT PS.ProductID, SUM(PS.QunatitSold) AS TotalQuantitySold FROM ProductSales PS GROUP BY PS.ProductID Without an index, SQL Server performs a Table Scan, which is expensive. 🔹 Step 1: Add Index on GROUP BY Column CREATE NONCLUSTERED INDEX IX_ProductSales_ProductID ON ProductSales(ProductID) Now SQL Server uses an Index Scan, but still performs RID Lookup, which adds overhead. 🔹 Step 2: Create a Better (Composite) Index CREATE NONCLUSTERED INDEX IX_ProductSales_ProductID_QunatitSold ON ProductSales(ProductID, QunatitSold) Now the query uses this optimized index, reducing extra lookups and improving performance. 🔹 What is a Covering Query? A query is called a Covering Query when all required columns are available in the index itself. Example: SELECT ProductID, QunatitSold FROM ProductSales Since both columns exist in the composite index, SQL Server does not need to access the table, making the query faster. ✅ Key Takeaways Index on GROUP BY columns improves performance Composite indexes reduce lookups Covering queries eliminate table access SQL Server automatically chooses the best execution plan. #SQLServer #Database #DataEngineering #DataAnalytics #SQL #TSQL #DatabasePerformance #QueryOptimization #Indexing #DataScience #SQLServerTips #SQLPerformance #QueryTuning #ExecutionPlan #DatabaseOptimization #IndexStrategy #CoveringIndex #GroupBy #TechLearning #LearnSQL #ArtificialIntelligence #BigData #CloudComputing #MicrosoftSQLServer #Azure #TechTrends #DigitalTransformation
To view or add a comment, sign in
-
-
🚧 SQL Server → PostgreSQL Migration: 2 Critical Challenges I Solved During migration, the toughest part was handling stored procedures behavior differences while ensuring zero backend changes. 🔴 Challenge 1: IN/OUT Parameters SQL Server: · OUT parameters are optional · Procedures return values without strict definition -- SQL Server CREATE PROCEDURE GetData @Id INT AS BEGIN SELECT * FROM Table1 WHERE Id = @Id END PostgreSQL: · OUT parameters must be defined · Execution pattern differs 🔴 Challenge 2: Multiple Result Sets SQL Server: · One procedure → multiple result sets SELECT * FROM ClientMaster; SELECT * FROM BankMaster; Backend consumes both outputs directly. PostgreSQL: · Cannot return multiple result sets directly ⚡ Combined Solution ✔ Converted Stored Procedures → PostgreSQL Functions ✔ Used **JSON/JSONB** to handle: · Multiple result sets · Output structure -- PostgreSQL (Concept) SELECT jsonb_build_object( 'clients', (SELECT json_agg(c) FROM client_master c), 'banks', (SELECT json_agg(b) FROM bank_master b) ); ✔ Maintained: · Same business logic · Same execution behavior · No backend code changes 🧠 Approach SQL Server Behavior ↓ Analyze Output Pattern ↓ Design Compatible Structure (JSON) ↓ Implement in PostgreSQL Function ↓ Validate with Backend 📊 Result ✅ Multiple datasets handled in single response ✅ No backend impact ✅ Clean and scalable approach 💡 Key Learning: When migrating across databases, feature parity is not guaranteed — designing the right abstraction (like JSON) is the real solution. #PostgreSQL #SQLServer #DatabaseMigration #JSON #DataEngineering #SQL
To view or add a comment, sign in
-
"My cousin said we should just use MySQL." -- actual client, last month. Your database is not a preference. It is an architectural decision that affects your speed, your scale, your cost, and your future. SQL is structured and relational -- perfect for data that follows strict rules. Think accounting, inventory, banking. NoSQL is flexible and document-based -- perfect for apps where the data shape changes. Think social feeds, product catalogues, real-time systems. Choosing the right data architecture is the part of my work most developers skip. I do not skip it. What database is your current product running on? #MySQL #SQL #NoSQL #database #scale #accounting #TechTalk
To view or add a comment, sign in
-
-
“Switching into data has been stretching me in unexpected ways…” Day 5 & 6 of Revisiting SQL I used to think SQL was just… SQL. Turns out, there are different flavours—and they don’t all behave the same way. Over the past two days, I explored: SQL Flavours Different database systems use their own versions of SQL, like: MySQL PostgreSQL SQL Server They share the same foundation, but differ in syntax and features. A Simple Difference Limiting results looks different depending on the system: - MySQL / PostgreSQL SELECT * FROM Customers LIMIT 3; - SQL Server SELECT TOP 3 * FROM Customers; Same goal… different approach. What About Their Servers? Each flavour runs on its own database system: MySQL → common for web applications PostgreSQL → more advanced, great for complex queries SQL Server → widely used in enterprise environments My Takeaway The syntax may change, but the thinking behind SQL stays the same. Once you understand the fundamentals, you can adapt to any environment. Still learning. Still building. I explored MySQL and PostgreSQL. Which of the above systems have you worked on? #SQL #DataLearning #TechJourney #WomenInTech #LearningInPublic
To view or add a comment, sign in
-
SQL Day 30 ( studying the NULL is not zero. NULL is "I don't know." 📌) Today I learned something that sounds simple but changes everything. NULL ≠ 0. NULL ≠ empty string. NULL = unknown. And if you don't handle it? Your calculations break. SQL has some built-in functions to handle NULL values, and the most common functions are: COALESCE() - The preferred standard. (Works in MySQL, SQL Server and Oracle) IFNULL() - (MySQL) ISNULL() - (SQL Server) NVL() - (Oracle) IsNull() - (MS Access) sql syntax SELECT COALESCE(column_name, 'No data') FROM table_name; If the column is NULL, show "No data" instead. Why this matters: A NULL value doesn't break your query anymore. You decide what fills the gap. #Data analytics #LearningSQL #DataJourney #SQLBeginners #WomeninTech
To view or add a comment, sign in
-
Many developers model everything as a table in PostgreSQL without knowing there's a feature that can make queries faster and simplify the database structure in certain cases: Composite Types. The idea is simple: you define a structured data type and use it as a column in any table When it makes sense to use: - The data has no identity of its own, it only exists alongside the parent record - You'll never query that data in isolation - You don't need history, auditing or traceability - It's a fixed, immutable value that just enriches the main row When it doesn't make sense and a 1:1 table is better: - The data can be referenced by other tables - You need history (the address changed and you want to keep the previous one) - It will grow over time and get new columns - Other parts of the application need to access that data directly The main tradeoff is: Composite Type eliminates the JOIN and makes reads faster, but you give up flexibility. If requirements change and that data needs to become its own entity, the migration is a pain. *If you use Prisma, pay attention: it doesn't natively map composite types, it treats the column as `Unsupported`. To read the data, you need to unpack the fields directly in SQL via `$queryRaw`. The rule I use to decide: if the data is a value that describes something, make it a type. If the data is an entity with a life of its own, make it a table. Follow me for more technical posts like this. #PostgreSQL #SQL #Database #Backend #FullStack #DatabaseDesign #Prisma
To view or add a comment, sign in
-
Explore related topics
- How to Optimize Postgresql Database Performance
- Database Performance Tuning
- How to Optimize SQL Server Performance
- How Indexing Improves Query Performance
- How to Improve NOSQL Database Performance
- How to Optimize Query Strategies
- How to Understand SQL Query Execution Order
- Tips for Database Performance Optimization
- How to Analyze Database Performance
- How to Optimize Cloud Database Performance
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development