Является ли первичный ключ проиндексированным в SQL?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Является ли первичный ключ проиндексированным в SQL?
Ответ: Да, первичный ключ (Primary Key) ВСЕГДА автоматически индексируется во всех основных системах управления базами данных (СУБД).
Это одна из основных характеристик первичного ключа и выполняется автоматически.
Почему первичный ключ индексируется
Первичный ключ по определению должен быть уникальным идентификатором каждой записи. Для обеспечения этого уникальности СУБД автоматически создаёт индекс, который:
- Гарантирует уникальность — поиск по первичному ключу должен быть быстрым и вернуть только одну запись
- Ускоряет поиск — индекс позволяет находить записи за O(log n) вместо O(n)
- Поддерживает целостность — предотвращает добавление дубликатов
SQL примеры
PostgreSQL
CREATE TABLE users (
id SERIAL PRIMARY KEY, -- Индекс создаётся АВТОМАТИЧЕСКИ
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE -- Отдельный индекс для UNIQUE
);
-- Проверяем индексы
\d users
-- Результат:
-- Public | users_pkey | index | postgres | users | btree | id
-- Public | users_email_key | index | postgres | users | btree | email
Примечание: В PostgreSQL индекс для PRIMARY KEY создаётся с именем <table>_pkey.
MySQL
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT, -- Индекс АВТОМАТИЧЕСКИ
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE -- Отдельный индекс
);
-- Проверяем индексы
SHOW INDEXES FROM users;
-- Результат:
-- users | 0 | PRIMARY | 1 | id | ... | BTREE |
-- users | 0 | email | 1 | email | ... | BTREE |
SQL Server
CREATE TABLE users (
id INT PRIMARY KEY, -- Индекс АВТОМАТИЧЕСКИ (CLUSTERED)
name NVARCHAR(100) NOT NULL,
email NVARCHAR(100) UNIQUE -- Отдельный индекс
);
-- Проверяем индексы
SP_HELPINDEX 'users';
Типы индексов для первичного ключа
1. Clustered Index (по умолчанию в SQL Server)
Данные физически отсортированы по первичному ключу.
Данные в диске:
id=1 | name=Alice
id=2 | name=Bob
id=3 | name=Charlie
id=4 | name=David
-- SQL Server: PRIMARY KEY создаёт CLUSTERED индекс
CREATE TABLE users (
id INT PRIMARY KEY, -- Автоматический CLUSTERED индекс
name VARCHAR(100)
);
Плюсы Clustered Index:
- Поиск по PRIMARY KEY максимально быстрый
- Последовательное сканирование быстрое
Минусы:
- Переиндексирование дорого (нужно пересортировать данные)
- Только один CLUSTERED индекс на таблицу
2. Non-Clustered Index (в PostgreSQL, MySQL)
Отдельная структура B-tree, которая указывает на данные.
Индекс (B-tree) Данные на диске
id=1 ──────→ 0x1000 | name=Alice
id=2 ──────→ 0x2000 | name=Bob
id=3 ──────→ 0x3000 | name=Charlie
-- PostgreSQL: PRIMARY KEY создаёт NON-CLUSTERED индекс
CREATE TABLE users (
id SERIAL PRIMARY KEY, -- Автоматический B-tree индекс
name VARCHAR(100)
);
Производительность поиска
Без индекса (Full Table Scan)
SELECT * FROM users WHERE id = 100;
-- О(n) — проверяет все n записей
-- 1 млн записей = 1 млн операций
С индексом (Index Seek)
SELECT * FROM users WHERE id = 100;
-- O(log n) — использует индекс
-- 1 млн записей = ~20 операций (log2(1000000) ≈ 20)
Практический пример: Java с JDBC
import java.sql.*;
public class PrimaryKeyIndexExample {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/mydb";
String user = "postgres";
String password = "password";
try (Connection conn = DriverManager.getConnection(url, user, password)) {
// 1. Создаём таблицу с PRIMARY KEY (индекс создаётся АВТОМАТИЧЕСКИ)
String createTableSQL = """n CREATE TABLE IF NOT EXISTS products (
product_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2)
)
""";
try (Statement stmt = conn.createStatement()) {
stmt.execute(createTableSQL);
}
// 2. Вставляем данные
String insertSQL = "INSERT INTO products (name, price) VALUES (?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
for (int i = 1; i <= 1000; i++) {
pstmt.setString(1, "Product " + i);
pstmt.setDouble(2, 10.0 + i);
pstmt.addBatch();
}
pstmt.executeBatch();
}
// 3. Поиск по PRIMARY KEY (использует индекс — быстро!)
String selectSQL = "SELECT * FROM products WHERE product_id = ?";
try (PreparedStatement pstmt = conn.prepareStatement(selectSQL)) {
pstmt.setInt(1, 500);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println("ID: " + rs.getInt("product_id"));
System.out.println("Name: " + rs.getString("name"));
System.out.println("Price: " + rs.getDouble("price"));
}
}
// 4. Проверяем индексы (PostgreSQL)
String indexSQL = """
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = 'products'
""";
try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery(indexSQL);
while (rs.next()) {
System.out.println("Индекс: " + rs.getString("indexname"));
System.out.println("Определение: " + rs.getString("indexdef"));
}
}
}
}
}
Когда PRIMARY KEY индекс используется
-- ✓ ИСПОЛЬЗУЕТСЯ индекс (быстро)
SELECT * FROM users WHERE id = 100;
SELECT * FROM users WHERE id IN (1, 2, 3);
SELECT * FROM users WHERE id > 100 AND id < 200;
SELECT * FROM users ORDER BY id; -- может использовать индекс
DELETE FROM users WHERE id = 100; -- использует индекс
UPDATE users SET name='John' WHERE id = 100; -- использует индекс
-- ✗ НЕ ИСПОЛЬЗУЕТСЯ индекс (может быть медленно)
SELECT * FROM users WHERE name = 'John'; -- нужен индекс на name
SELECT * FROM users WHERE UPPER(id) = '100'; -- функция на индексированном поле
SELECT * FROM users; -- FULL TABLE SCAN
Проверка плана выполнения
-- PostgreSQL
EXPLAIN ANALYZE
SELECT * FROM users WHERE id = 100;
-- Результат:
-- Index Scan using users_pkey on users (cost=0.29..8.30 rows=1) ✓
-- MySQL
EXPLAIN
SELECT * FROM users WHERE id = 100;
-- Результат:
-- type: const ✓
-- key: PRIMARY
-- rows: 1
Важные замечания
-
Индекс создаётся АВТОМАТИЧЕСКИ — не нужно создавать отдельный индекс для PRIMARY KEY
-
Нельзя отключить индекс — первичный ключ всегда индексируется
-
Один CLUSTERED индекс на таблицу (в SQL Server) — PRIMARY KEY обычно становится CLUSTERED индексом
-
Индекс занимает место — на диске занимает дополнительное пространство (обычно 10-20% от размера таблицы)
-
Замедляет вставку/удаление — СУБД должна обновлять индекс при каждой операции
Вывод
Да, первичный ключ ВСЕГДА автоматически индексируется во всех основных СУБД. Это один из ключевых свойств первичного ключа и выполняется без явного указания разработчика. Индекс гарантирует:
- Быстрый поиск по PRIMARY KEY (O(log n))
- Уникальность значений
- Оптимизацию JOIN операций
Поэтому выбор первичного ключа критичен для производительности — лучше использовать числовые типы (INT, BIGINT) вместо строк, так как они быстрее индексируются.