00:00

MySQL Table Vs View

Last updated: 5 min read

Tables and views look the same when you query them: both have columns and return rows. Underneath, they are very different. A table stores data. A view stores a query. This page compares them side by side with examples, so you know which to use and when.

1. The Core Difference

Table versus viewA table stores rows on disk and has its own indexes. A view stores only a SELECT statement; when queried it reads the rows from the underlying tables.Tablerowson diskindexesconstraintsstores dataViewSELECT name, planFROM members WHERE activestores only the queryreads the table each time
Figure 1: a table holds data; a view holds a query that reads data from tables.
TableView
What it storesRows of dataOnly a SELECT statement
Disk spaceGrows with the dataAlmost none (just the definition)
Created withCREATE TABLECREATE VIEW … AS SELECT
Data freshnessWhatever was last writtenAlways current: query runs at read time
IndexesCan have its own indexesNo own indexes; uses the base tables' indexes
INSERT / UPDATE / DELETEAlwaysOnly for simple, updatable views
Constraints / triggersYesNo (WITH CHECK OPTION is the only rule)
Dropping itDeletes the dataDeletes only the query
Typical useSystem of recordSimplify queries, hide columns, stable interface

2. Same Question, Table vs View

Let's answer "total paid per customer" both ways. First as a view:

as-view.sql
CREATE VIEW paid_totals_v AS
SELECT customer, SUM(amount) AS total_paid
FROM orders WHERE status = 'paid'
GROUP BY customer;

SELECT * FROM paid_totals_v ORDER BY total_paid DESC;

Result: 2 rows

customertotal_paid
Ritu4450.00
Sahil990.00

Then as a table (a snapshot of the same result):

as-table.sql
CREATE TABLE paid_totals_t AS
SELECT customer, SUM(amount) AS total_paid
FROM orders WHERE status = 'paid'
GROUP BY customer;

SELECT * FROM paid_totals_t ORDER BY total_paid DESC;

Result: 2 rows

customertotal_paid
Ritu4450.00
Sahil990.00

3. Freshness: Watch Them Diverge

Now Sahil's pending order is paid:

diverge.sql
UPDATE orders SET status = 'paid' WHERE order_id = 2;

SELECT 'view'  AS source, customer, total_paid FROM paid_totals_v WHERE customer = 'Sahil'
UNION ALL
SELECT 'table' AS source, customer, total_paid FROM paid_totals_t WHERE customer = 'Sahil';

Result: 2 rows

sourcecustomertotal_paid
viewSahil1470.00
tableSahil990.00

The view picked up the change immediately; the table still shows the old total until you rebuild or update it.

4. Storage

query.sql
SELECT table_name, table_type, data_length
FROM information_schema.tables
WHERE table_schema = 'store'
ORDER BY table_type, table_name;

Result: 3 rows

TABLE_NAMETABLE_TYPEDATA_LENGTH
ordersBASE TABLE16384
paid_totals_tBASE TABLE16384
paid_totals_vVIEWNULL

The view has no data length at all (NULL); the tables have allocated pages.

5. Changing Data

You can always change a table. An aggregate view can't be changed, because there's no single row to update:

query.sql
UPDATE paid_totals_v SET total_paid = 0 WHERE customer = 'Ritu';
Output
ERROR 1288 (HY000): The target table paid_totals_v of the UPDATE is not updatable

A simple view on one table can be updated, and the change goes to the base table:

updatable.sql
CREATE VIEW pending_orders AS SELECT order_id, status FROM orders WHERE status = 'pending';
INSERT INTO orders VALUES (6, 'Ritu', 700, 'pending', '2026-03-04');
UPDATE pending_orders SET status = 'paid' WHERE order_id = 6;
SELECT order_id, status FROM orders WHERE order_id = 6;

Result: 1 row

order_idstatus
6paid

6. Performance

  • A view adds no speed by itself: querying it runs the underlying SELECT each time.
  • With the MERGE algorithm, MySQL folds the view into your query, so indexes on the base tables still help.
  • A summary table answers instantly but needs refreshing (on a schedule, with an event, or by triggers).
  • MySQL has no materialized views; a summary table plus a scheduled refresh is the usual substitute.
refresh.sql
-- refresh the snapshot table on demand
TRUNCATE TABLE paid_totals_t;
INSERT INTO paid_totals_t
SELECT customer, SUM(amount) FROM orders WHERE status = 'paid' GROUP BY customer;
SELECT * FROM paid_totals_t ORDER BY customer;

Result: 2 rows

customertotal_paid
Ritu5150.00
Sahil1470.00

7. Security

Both can be granted to users, but a view can expose part of a table. Granting SELECT on a view of only customer and status keeps amount private, without copying data into a separate table that must be kept in sync.

8. When to Use Which

Use a table when…Use a view when…
You need to store new facts (orders, users, events)You keep writing the same complex query
You need indexes, constraints and triggersYou want to hide columns or rows from some users
You need a fast, pre-computed summary (refreshed periodically)Results must always be up to date
Data must survive changes to other tablesYou want a stable interface while tables change underneath

9. Practice Exercises

Exercise 1: Create a view daily_sales with the total paid amount per day.
solution.sql
CREATE VIEW daily_sales AS
SELECT ordered_on, SUM(amount) AS total
FROM orders WHERE status = 'paid'
GROUP BY ordered_on;
SELECT * FROM daily_sales ORDER BY ordered_on;

Result: 4 rows

ordered_ontotal
2026-03-011730.00
2026-03-023200.00
2026-03-03990.00
2026-03-04700.00
Exercise 2: Is daily_sales updatable? Check with information_schema.
solution.sql
SELECT table_name, is_updatable FROM information_schema.views WHERE table_schema = 'store';

Result: 3 rows

TABLE_NAMEIS_UPDATABLE
daily_salesNO
paid_totals_vNO
pending_ordersYES

10. Summary

  • A table stores data; a view stores a SELECT and reads data when queried.
  • Views are always current and use no data space; tables keep whatever was written.
  • Tables support indexes, constraints and triggers; only simple views are updatable.
  • Use views to simplify and secure; use (summary) tables when you need stored or pre-computed data.