测试与优化

master
苗新成 3 months ago
parent 2d4f1424ca
commit ec28899da3

@ -0,0 +1,92 @@
-- ============================================
-- 功能04优化医生当日待诊列表
-- ============================================
WITH schedule_ids AS (
SELECT schedule_id
FROM schedule
WHERE doctor_id = '550e8400-e29b-41d4-a716-446655440004'
AND work_date = '2024-12-15'
),
appointment_data AS (
SELECT a.appointment_id, a.patient_id, a.appointment_time
FROM appointment a
WHERE a.schedule_id IN (SELECT schedule_id FROM schedule_ids)
AND a.status = 'scheduled'
)
SELECT
ad.appointment_id,
p.name AS patient_name,
ad.appointment_time
FROM appointment_data ad
JOIN patient p ON ad.patient_id = p.patient_id
ORDER BY ad.appointment_time;
-- ============================================
-- 功能13优化扣减药品库存
-- ============================================
-- 优化后(使用索引覆盖)
CREATE INDEX idx_inventory_batch_drug_stock_expiry_covering
ON inventory_batch(drug_id, current_stock, expiry_date)
INCLUDE (batch_id);
-- 然后使用索引优化查询
EXPLAIN (ANALYZE, VERBOSE)
SELECT batch_id
FROM inventory_batch
WHERE drug_id = '550e8400-e29b-41d4-a716-446655440018'
AND current_stock >= 10
ORDER BY expiry_date
LIMIT 1;
-- ============================================
-- 功能18优化统计医生工作量
-- ============================================
-- 优化后(使用日期范围,可索引优化)
SELECT d.name,
COUNT(mr.record_id) as record_count
FROM doctor d
LEFT JOIN medical_record mr ON d.doctor_id = mr.doctor_id
AND mr.visit_time >= '2024-12-01'::date
AND mr.visit_time < '2025-01-01'::date
WHERE d.work_status = 'active'
GROUP BY d.doctor_id, d.name;
-- ============================================
-- 功能16优化查询库存预警药品
-- ============================================
-- 优化后使用子查询减少JOIN
WITH drug_stock AS (
SELECT
drug_id,
SUM(current_stock) as total_stock,
MIN(min_stock_threshold) as min_threshold
FROM inventory_batch
GROUP BY drug_id
HAVING SUM(current_stock) < MIN(min_stock_threshold)
)
SELECT
d.generic_name,
ds.total_stock,
ds.min_threshold
FROM drug_stock ds
JOIN drug d ON ds.drug_id = d.drug_id;
-- ============================================
-- 功能16优化查询库存预警药品
-- ============================================
-- 优化后减少JOIN层级使用子查询
SELECT
dep.name,
COALESCE(apt_stats.appointment_count, 0) as appointment_count
FROM department dep
LEFT JOIN (
SELECT
d.department_id,
COUNT(a.appointment_id) as appointment_count
FROM doctor d
JOIN schedule s ON d.doctor_id = s.doctor_id
LEFT JOIN appointment a ON s.schedule_id = a.schedule_id
WHERE s.work_date = '2024-12-15'
GROUP BY d.department_id
) apt_stats ON dep.department_id = apt_stats.department_id
ORDER BY dep.name;

@ -0,0 +1,234 @@
### 索引优化策略
```sql
-- 1. 排班表索引优化
CREATE INDEX IF NOT EXISTS idx_schedule_doctor_date_remain
ON schedule(doctor_id, work_date, remaining_appointments);
-- 2. 预约表索引优化
CREATE INDEX IF NOT EXISTS idx_appointment_schedule_status_time
ON appointment(schedule_id, status, appointment_time);
CREATE INDEX IF NOT EXISTS idx_appointment_status
ON appointment(status);
-- 3. 库存批次表索引优化
CREATE INDEX IF NOT EXISTS idx_inventory_batch_drug_stock_expiry
ON inventory_batch(drug_id, current_stock, expiry_date);
-- 4. 药品表索引优化(已有主键索引)
CREATE INDEX IF NOT EXISTS idx_drug_generic_name
ON drug(generic_name);
-- 5. 医生表索引优化
CREATE INDEX IF NOT EXISTS idx_doctor_status
ON doctor(work_status);
-- 6. 电子病历表索引优化
CREATE INDEX IF NOT EXISTS idx_medical_record_doctor_visit
ON medical_record(doctor_id, visit_time);
-- 7. 处方明细表索引优化
CREATE INDEX IF NOT EXISTS idx_prescription_item_prescription
ON prescription_item(prescription_id);
-- 8. 患者表索引优化
CREATE INDEX IF NOT EXISTS idx_patient_name
ON patient(name);
```
### 查询重写优化
#### 功能04优化医生当日待诊列表
```sql
-- 优化前存在Seq Scan
EXPLAIN (ANALYZE, VERBOSE)
SELECT a.appointment_id, p.name AS patient_name, a.appointment_time
FROM appointment a
JOIN patient p ON a.patient_id = p.patient_id
JOIN schedule s ON a.schedule_id = s.schedule_id
WHERE s.doctor_id = '550e8400-e29b-41d4-a716-446655440004'
AND s.work_date = '2024-12-15'
AND a.status = 'scheduled'
ORDER BY a.appointment_time;
-- 优化后使用CTE和优化JOIN顺序
WITH schedule_ids AS (
SELECT schedule_id
FROM schedule
WHERE doctor_id = '550e8400-e29b-41d4-a716-446655440004'
AND work_date = '2024-12-15'
),
appointment_data AS (
SELECT a.appointment_id, a.patient_id, a.appointment_time
FROM appointment a
WHERE a.schedule_id IN (SELECT schedule_id FROM schedule_ids)
AND a.status = 'scheduled'
)
SELECT
ad.appointment_id,
p.name AS patient_name,
ad.appointment_time
FROM appointment_data ad
JOIN patient p ON ad.patient_id = p.patient_id
ORDER BY ad.appointment_time;
```
| | | | | | | | | |
|---|---|---|---|---|---|---|---|---|
|SELECT (select)||||||||Planning Time = 0.323; Triggers = []; Execution Time = 0.031;|
|SORT (sort)||1|0|17.18|0.012|17.17|0.012|Parallel Aware = false; Async Capable = false; Plan Width = 32; Actual Loops = 1; Sort Key = ["a.appointment_time"]; Sort Method = quicksort; Sort Space Used = 25; Sort Space Type = Memory;|
|NESTED_LOOPS (Nested Loop)||1|0|17.16|0.008|0.98|0.008|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Inner; Plan Width = 32; Actual Loops = 1; Inner Unique = true;|
|NESTED_LOOPS (Nested Loop)||1|0|16.75|0.008|0.7|0.008|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Inner; Plan Width = 40; Actual Loops = 1; Inner Unique = false;|
|INDEX_SCAN (index scan)|table: schedule; index: idx_schedule_doctor_date_remain;|1|0|8.31|0.008|0.29|0.008|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Scan Direction = Forward; Alias = schedule; Plan Width = 16; Actual Loops = 1; Index Cond = ((doctor_id = '550e8400-e29b-41d4-a716-446655440004'::uuid) AND (work_date = '2024-12-15'::date)); Rows Removed by Index Recheck = 0;|
|INDEX_SCAN (index scan)|table: appointment; index: idx_appointment_schedule_status_time;|1|0|8.43|0.0|0.41|0.0|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Scan Direction = Forward; Alias = a; Plan Width = 56; Actual Loops = 0; Index Cond = ((schedule_id = schedule.schedule_id) AND ((status)::text = 'scheduled'::text)); Rows Removed by Index Recheck = 0;|
|INDEX_SCAN (index scan)|table: patient; index: patient_pkey;|1|0|0.41|0.0|0.29|0.0|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Scan Direction = Forward; Alias = p; Plan Width = 24; Actual Loops = 0; Index Cond = (patient_id = a.patient_id); Rows Removed by Index Recheck = 0;|
#### 功能13优化扣减药品库存
```sql
-- 优化前(全表扫描+排序)
EXPLAIN (ANALYZE, VERBOSE)
SELECT batch_id FROM inventory_batch
WHERE drug_id = '550e8400-e29b-41d4-a716-446655440018'
AND current_stock >= 10
ORDER BY expiry_date ASC LIMIT 1;
-- 优化后(使用索引覆盖)
CREATE INDEX idx_inventory_batch_drug_stock_expiry_covering
ON inventory_batch(drug_id, current_stock, expiry_date)
INCLUDE (batch_id);
-- 然后使用索引优化查询
EXPLAIN (ANALYZE, VERBOSE)
SELECT batch_id
FROM inventory_batch
WHERE drug_id = '550e8400-e29b-41d4-a716-446655440018'
AND current_stock >= 10
ORDER BY expiry_date ASC
LIMIT 1;
```
Limit (cost=4.41..4.41 rows=1 width=20) (actual time=0.071..0.072 rows=0 loops=1)
" Output: batch_id, expiry_date"
-> Sort (cost=4.41..4.42 rows=5 width=20) (actual time=0.071..0.071 rows=0 loops=1)
" Output: batch_id, expiry_date"
Sort Key: inventory_batch.expiry_date
Sort Method: quicksort Memory: 25kB
-> Index Only Scan using idx_inventory_batch_drug_stock_expiry_covering on hms.inventory_batch (cost=0.28..4.38 rows=5 width=20) (actual time=0.067..0.067 rows=0 loops=1)
" Output: batch_id, expiry_date"
Index Cond: ((inventory_batch.drug_id = '550e8400-e29b-41d4-a716-446655440018'::uuid) AND (inventory_batch.current_stock >= 10))
Heap Fetches: 0
Planning Time: 1.619 ms
Execution Time: 0.095 ms
#### 功能18优化统计医生工作量
```sql
-- 优化前使用EXTRACT函数无法使用索引
SELECT d.name, COUNT(mr.record_id) as record_count
FROM doctor d
LEFT JOIN medical_record mr ON d.doctor_id = mr.doctor_id
AND EXTRACT(YEAR FROM mr.visit_time) = 2024
AND EXTRACT(MONTH FROM mr.visit_time) = 12
WHERE d.work_status = 'active'
GROUP BY d.doctor_id, d.name;
-- 优化后(使用日期范围,可索引优化)
SELECT
d.name,
COUNT(mr.record_id) as record_count
FROM doctor d
LEFT JOIN medical_record mr ON d.doctor_id = mr.doctor_id
AND mr.visit_time >= '2024-12-01'::date
AND mr.visit_time < '2025-01-01'::date
WHERE d.work_status = 'active'
GROUP BY d.doctor_id, d.name;
```
| | | | | | | | | |
|---|---|---|---|---|---|---|---|---|
|SELECT (select)||||||||Planning Time = 0.244; Triggers = []; Execution Time = 1.622;|
|AGGREGATE (aggregate)||1194|1194|2966.52|1.514|2954.58|1.446|Strategy = Hashed; Partial Mode = Simple; Parallel Aware = false; Async Capable = false; Plan Width = 32; Actual Loops = 1; Group Key = ["d.doctor_id"]; Planned Partitions = 0; HashAgg Batches = 1; Peak Memory Usage = 193; Disk Usage = 0;|
|HASH_JOIN (hash join)||1194|1295|2948.61|1.284|672.45|0.725|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Right; Plan Width = 40; Actual Loops = 1; Inner Unique = true; Hash Cond = (mr.doctor_id = d.doctor_id);|
|BITMAP_INDEX_SCAN (Bitmap Heap Scan)|table: medical_record;|899|865|2878.32|0.834|604.52|0.414|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = mr; Plan Width = 32; Actual Loops = 1; Recheck Cond = ((visit_time >= '2024-12-01'::date) AND (visit_time < '2025-01-01'::date)); Rows Removed by Index Recheck = 0; Exact Heap Blocks = 781; Lossy Heap Blocks = 0;|
|BITMAP_INDEX_SCAN (bitmap index scan)|index: idx_medical_record_doctor_visit;|899|865|604.3|0.354|0.0|0.354|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Plan Width = 0; Actual Loops = 1; Index Cond = ((visit_time >= '2024-12-01'::date) AND (visit_time < '2025-01-01'::date));|
|TRANSFORM (Hash)||1194|1194|53.0|0.303|53.0|0.303|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Plan Width = 24; Actual Loops = 1; Hash Buckets = 2048; Original Hash Buckets = 2048; Hash Batches = 1; Original Hash Batches = 1; Peak Memory Usage = 82;|
|SEQ_SCAN (Seq Scan)|table: doctor;|1194|1194|53.0|0.201|0.0|0.013|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = d; Plan Width = 24; Actual Loops = 1; Filter = ((work_status)::text = 'active'::text); Rows Removed by Filter = 806;|
#### 功能16优化查询库存预警药品
```sql
-- 优化前Hash Join + 全表扫描)
SELECT d.generic_name, SUM(ib.current_stock) AS total_stock
FROM drug d
JOIN inventory_batch ib ON d.drug_id = ib.drug_id
GROUP BY d.drug_id, d.generic_name, ib.min_stock_threshold
HAVING SUM(ib.current_stock) < ib.min_stock_threshold;
-- 优化后使用子查询减少JOIN
WITH drug_stock AS (
SELECT
drug_id,
SUM(current_stock) as total_stock,
MIN(min_stock_threshold) as min_threshold
FROM inventory_batch
GROUP BY drug_id
HAVING SUM(current_stock) < MIN(min_stock_threshold)
)
SELECT
d.generic_name,
ds.total_stock,
ds.min_threshold
FROM drug_stock ds
JOIN drug d ON ds.drug_id = d.drug_id;
```
| | | | | | | | | |
|---|---|---|---|---|---|---|---|---|
|SELECT (select)||||||||Planning Time = 1.723; Triggers = []; Execution Time = 1.241;|
|HASH_JOIN (hash join)||331|0|231.01|1.191|194.37|1.19|Parallel Aware = false; Async Capable = false; Join Type = Inner; Plan Width = 21; Actual Loops = 1; Inner Unique = true; Hash Cond = (d.drug_id = ds.drug_id);|
|SEQ_SCAN (Seq Scan)|table: drug;|1000|1|34.0|0.01|0.0|0.009|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = d; Plan Width = 25; Actual Loops = 1;|
|TRANSFORM (Hash)||331|0|190.24|1.176|190.24|1.175|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Plan Width = 28; Actual Loops = 1; Hash Buckets = 1024; Original Hash Buckets = 1024; Hash Batches = 1; Original Hash Batches = 1; Peak Memory Usage = 8;|
|ACCESS (Subquery Scan)||331|0|190.24|1.175|174.5|1.175|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = ds; Plan Width = 28; Actual Loops = 1;|
|AGGREGATE (aggregate)||331|0|186.93|1.175|174.5|1.175|Strategy = Hashed; Partial Mode = Simple; Parent Relationship = Subquery; Parallel Aware = false; Async Capable = false; Plan Width = 28; Actual Loops = 1; Group Key = ["inventory_batch.drug_id"]; Filter = (sum(inventory_batch.current_stock) < min(inventory_batch.min_stock_threshold)); Planned Partitions = 0; HashAgg Batches = 1; Peak Memory Usage = 193; Disk Usage = 0; Rows Removed by Filter = 994;|
|SEQ_SCAN (Seq Scan)|table: inventory_batch;|5000|5000|137.0|0.22|0.0|0.005|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = inventory_batch; Plan Width = 24; Actual Loops = 1;|
#### 功能17优化统计科室预约量
```sql
-- 优化前(复杂嵌套循环)
SELECT dep.name, COUNT(a.appointment_id) as appointment_count
FROM department dep
JOIN doctor d ON dep.department_id = d.department_id
JOIN schedule s ON d.doctor_id = s.doctor_id
LEFT JOIN appointment a ON s.schedule_id = a.schedule_id
WHERE s.work_date = '2024-12-15'
GROUP BY dep.department_id, dep.name;
-- 优化后减少JOIN层级使用子查询
SELECT
dep.name,
COALESCE(apt_stats.appointment_count, 0) as appointment_count
FROM department dep
LEFT JOIN (
SELECT
d.department_id,
COUNT(a.appointment_id) as appointment_count
FROM doctor d
JOIN schedule s ON d.doctor_id = s.doctor_id
LEFT JOIN appointment a ON s.schedule_id = a.schedule_id
WHERE s.work_date = '2024-12-15'
GROUP BY d.department_id
) apt_stats ON dep.department_id = apt_stats.department_id
ORDER BY dep.name;
```
| | | | | | |
|---|---|---|---|---|---|
|SELECT (select)||||||
|SORT (sort)||100|702.93|702.68|Parallel Aware = false; Async Capable = false; Plan Width = 226; Sort Key = ["dep.name"];|
|HASH_JOIN (hash join)||100|699.36|688.08|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Left; Plan Width = 226; Inner Unique = true; Hash Cond = (dep.department_id = apt_stats.department_id);|
|SEQ_SCAN (Seq Scan)|table: department;|100|11.0|0.0|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = dep; Plan Width = 234;|
|TRANSFORM (Hash)||1|688.07|688.07|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Plan Width = 24;|
|ACCESS (Subquery Scan)||1|688.07|688.04|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = apt_stats; Plan Width = 24;|
|AGGREGATE (aggregate)||1|688.06|688.04|Strategy = Sorted; Partial Mode = Simple; Parent Relationship = Subquery; Parallel Aware = false; Async Capable = false; Plan Width = 24; Group Key = ["d.department_id"];|
|SORT (sort)||1|688.05|688.04|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Plan Width = 32; Sort Key = ["d.department_id"];|
|NESTED_LOOPS (Nested Loop)||1|688.03|0.69|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Left; Plan Width = 32; Inner Unique = false;|
|NESTED_LOOPS (Nested Loop)||1|679.59|0.28|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Inner; Plan Width = 32; Inner Unique = true;|
|SEQ_SCAN (Seq Scan)|table: schedule;|1|671.29|0.0|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = s; Plan Width = 32; Filter = (work_date = '2024-12-15'::date);|
|INDEX_SCAN (index scan)|table: doctor; index: doctor_pkey;|1|8.29|0.28|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Scan Direction = Forward; Alias = d; Plan Width = 32; Index Cond = (doctor_id = s.doctor_id);|
|INDEX_SCAN (index scan)|table: appointment; index: idx_appointment_schedule_status_time;|1|8.43|0.41|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Scan Direction = Forward; Alias = a; Plan Width = 32; Index Cond = (schedule_id = s.schedule_id);|

@ -0,0 +1,252 @@
-- ============================================
-- 原始SQL测试文件
-- 医院管理系统查询性能测试
-- 测试环境PostgreSQL 17DataGrip 2025.2.5
-- 数据规模:万级到十万级
-- ============================================
-- ============================================
-- 功能01查询医生排班号源
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT schedule_id, slot_no, remaining_appointments
FROM schedule
WHERE doctor_id = '550e8400-e29b-41d4-a716-446655440000'
AND work_date = '2024-12-15'
AND remaining_appointments > 0;
-- ============================================
-- 功能02扣减排班号源
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE schedule SET remaining_appointments = remaining_appointments - 1
WHERE schedule_id = '550e8400-e29b-41d4-a716-446655440001';
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能03创建预约记录
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
INSERT INTO appointment (appointment_id, patient_id, schedule_id, appointment_time, status)
VALUES (gen_random_uuid(), '89c5bb83-c039-4619-b458-7afe7a31fc64',
'8510e8ab-37eb-4b12-b69d-f24c076845ca',
'2024-12-15 09:30:00', 'scheduled');
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能04查询医生当日待诊列表
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT a.appointment_id, p.name AS patient_name, a.appointment_time
FROM appointment a
JOIN patient p ON a.patient_id = p.patient_id
JOIN schedule s ON a.schedule_id = s.schedule_id
WHERE s.doctor_id = '550e8400-e29b-41d4-a716-446655440004'
AND s.work_date = '2024-12-15'
AND a.status = 'scheduled'
ORDER BY a.appointment_time;
-- ============================================
-- 功能05更新预约状态为"已签到"
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE appointment SET status = 'checked_in'
WHERE appointment_id = '550e8400-e29b-41d4-a716-446655440005';
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能06创建初始病历记录
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
INSERT INTO medical_record (record_id, patient_id, doctor_id, appointment_id, visit_time)
VALUES (gen_random_uuid(), '5e8d512a-22c9-4272-9cc7-b5b602b447c6',
'51e660c9-8270-439b-b33a-12230b5f27b2',
'3221a9b3-05e2-4375-92ce-f395ca05115f',
CURRENT_TIMESTAMP);
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能07更新病历诊断信息
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE medical_record
SET chief_complaint = '头痛、发热3天',
diagnosis_codes = '上呼吸道感染,高血压',
updated_at = CURRENT_TIMESTAMP
WHERE record_id = '550e8400-e29b-41d4-a716-446655440009';
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能08创建处方主记录
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
INSERT INTO prescription (prescription_id, record_id, doctor_id, status)
VALUES ('5fcd0fcb-e522-43fb-b82e-8270c70aeb03', '05e5fe94-6b58-4e08-ae06-fc6990793c29',
'0193cd15-f4c4-4331-beaa-01fb67a3d00c', 'pending');
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能09添加处方明细项
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
INSERT INTO prescription_item (item_id, prescription_id, drug_id, dosage, frequency, duration_days, quantity)
VALUES (gen_random_uuid(), '550e8400-e29b-51d4-a716-446655440012',
'550e8400-e29b-41d4-a716-446655440013',
'1片', '每日3次', 7, 21);
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能10查询处方明细清单
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT d.generic_name, i.dosage, i.frequency, i.quantity
FROM prescription_item i
JOIN drug d ON i.drug_id = d.drug_id
WHERE i.prescription_id = '550e8400-e29b-41d4-a716-446655440014';
-- ============================================
-- 功能11更新处方审核状态
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE prescription SET status = 'approved',
pharmacist_id = '550e8400-e29b-41d4-a716-446655440015',
reviewed_at = CURRENT_TIMESTAMP
WHERE prescription_id = '550e8400-e29b-41d4-a716-446655440016';
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能12查询药品库存可用数量
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT SUM(current_stock) AS total_stock
FROM inventory_batch
WHERE drug_id = '550e8400-e29b-41d4-a716-446655440017';
-- ============================================
-- 功能13扣减药品库存
-- ============================================
-- 查询符合条件的批次(用于查看执行计划)
EXPLAIN (ANALYZE, VERBOSE)
SELECT batch_id FROM inventory_batch
WHERE drug_id = '550e8400-e29b-41d4-a716-446655440018'
AND current_stock >= 10
ORDER BY expiry_date
LIMIT 1;
-- ============================================
-- 功能14更新处方状态为"已发药"
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE prescription SET status = 'dispensed'
WHERE prescription_id = '550e8400-e29b-41d4-a716-446655440020';
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能15取消预约并回退号源
-- ============================================
-- 更新预约状态
EXPLAIN (ANALYZE, VERBOSE)
UPDATE appointment SET status = 'cancelled', cancelled_at = CURRENT_TIMESTAMP
WHERE appointment_id = '550e8400-e29b-41d4-a716-446655440021';
-- 回滚以保持数据一致性
ROLLBACK;
-- 回退号源(子查询版本)
EXPLAIN (ANALYZE, VERBOSE)
UPDATE schedule SET remaining_appointments = remaining_appointments + 1
WHERE schedule_id = (SELECT schedule_id FROM appointment
WHERE appointment_id = '550e8400-e29b-41d4-a716-446655440022');
-- 回滚以保持数据一致性
ROLLBACK;
-- ============================================
-- 功能16查询库存预警药品
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT d.generic_name, SUM(ib.current_stock) AS total_stock
FROM drug d
JOIN inventory_batch ib ON d.drug_id = ib.drug_id
GROUP BY d.drug_id, d.generic_name, ib.min_stock_threshold
HAVING SUM(ib.current_stock) < ib.min_stock_threshold;
-- ============================================
-- 功能17统计科室预约量
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT dep.name, COUNT(a.appointment_id) as appointment_count
FROM department dep
JOIN doctor d ON dep.department_id = d.department_id
JOIN schedule s ON d.doctor_id = s.doctor_id
LEFT JOIN appointment a ON s.schedule_id = a.schedule_id
WHERE s.work_date = '2024-12-15'
GROUP BY dep.department_id, dep.name;
-- ============================================
-- 功能18统计医生工作量
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT d.name, COUNT(mr.record_id) as record_count
FROM doctor d
LEFT JOIN medical_record mr ON d.doctor_id = mr.doctor_id
AND EXTRACT(YEAR FROM mr.visit_time) = 2024
AND EXTRACT(MONTH FROM mr.visit_time) = 12
WHERE d.work_status = 'active'
GROUP BY d.doctor_id, d.name;
-- ============================================
-- 数据分布统计(基本版)
-- ============================================
-- 1. 各表数据量统计
SELECT 'department' as table_name, COUNT(*) as row_count FROM department
UNION ALL
SELECT 'doctor', COUNT(*) FROM doctor
UNION ALL
SELECT 'patient', COUNT(*) FROM patient
UNION ALL
SELECT 'drug', COUNT(*) FROM drug
UNION ALL
SELECT 'inventory_batch', COUNT(*) FROM inventory_batch
UNION ALL
SELECT 'schedule', COUNT(*) FROM schedule
UNION ALL
SELECT 'appointment', COUNT(*) FROM appointment
UNION ALL
SELECT 'medical_record', COUNT(*) FROM medical_record
UNION ALL
SELECT 'prescription', COUNT(*) FROM prescription
UNION ALL
SELECT 'prescription_item', COUNT(*) FROM prescription_item;
-- 2. 现有索引检查
SELECT
t.relname as table_name,
i.relname as index_name,
a.attname as column_name
FROM pg_class t
JOIN pg_index ix ON t.oid = ix.indrelid
JOIN pg_class i ON i.oid = ix.indexrelid
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey)
WHERE t.relkind = 'r'
AND t.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public')
ORDER BY t.relname, i.relname;

@ -0,0 +1,469 @@
```sql
-- ============================================
-- 功能01查询医生排班号源
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT schedule_id, slot_no, remaining_appointments
FROM schedule
WHERE doctor_id = '550e8400-e29b-41d4-a716-446655440000'
AND work_date = '2024-12-15'
AND remaining_appointments > 0;
```
Index Scan using schedule_doctor_id_work_date_slot_no_key on hms.schedule (cost=0.29..8.31 rows=1 width=22) (actual time=0.042..0.042 rows=0 loops=1)
" Output: schedule_id, slot_no, remaining_appointments"
Index Cond: ((schedule.doctor_id = '550e8400-e29b-41d4-a716-446655440000'::uuid) AND (schedule.work_date = '2024-12-15'::date))
Filter: (schedule.remaining_appointments > 0)
Planning Time: 0.201 ms
Execution Time: 0.063 ms
```sql
-- ============================================
-- 功能02扣减排班号源
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE schedule SET remaining_appointments = remaining_appointments - 1
WHERE schedule_id = '550e8400-e29b-41d4-a716-446655440001';
```
Update on hms.schedule (cost=0.29..8.31 rows=0 width=0) (actual time=0.026..0.026 rows=0 loops=1)
-> Index Scan using schedule_pkey on hms.schedule (cost=0.29..8.31 rows=1 width=10) (actual time=0.018..0.018 rows=0 loops=1)
" Output: (remaining_appointments - 1), ctid"
Index Cond: (schedule.schedule_id = '550e8400-e29b-41d4-a716-446655440001'::uuid)
Planning Time: 0.095 ms
Execution Time: 0.245 ms
```sql
-- ============================================
-- 功能03创建预约记录
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
INSERT INTO appointment (appointment_id, patient_id, schedule_id, appointment_time, status)
VALUES (gen_random_uuid(), '89c5bb83-c039-4619-b458-7afe7a31fc64',
'8510e8ab-37eb-4b12-b69d-f24c076845ca',
'2024-12-15 09:30:00', 'scheduled');
```
Insert on hms.appointment (cost=0.00..0.02 rows=0 width=0) (actual time=0.078..0.078 rows=0 loops=1)
-> Result (cost=0.00..0.02 rows=1 width=704) (actual time=0.018..0.018 rows=1 loops=1)
" Output: gen_random_uuid(), '89c5bb83-c039-4619-b458-7afe7a31fc64'::uuid, '8510e8ab-37eb-4b12-b69d-f24c076845ca'::uuid, '2024-12-15 09:30:00'::timestamp without time zone, 'scheduled'::character varying(20), 'online'::character varying(20), CURRENT_TIMESTAMP, NULL::timestamp without time zone, NULL::character varying(255)"
Planning Time: 0.022 ms
Trigger RI_ConstraintTrigger_c_27573 for constraint fk_apt_patient: time=0.082 calls=1
Trigger RI_ConstraintTrigger_c_27578 for constraint fk_apt_schedule: time=0.044 calls=1
Execution Time: 0.215 ms
```sql
-- ============================================
-- 功能04查询医生当日待诊列表
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT a.appointment_id, p.name AS patient_name, a.appointment_time
FROM appointment a
JOIN patient p ON a.patient_id = p.patient_id
JOIN schedule s ON a.schedule_id = s.schedule_id
WHERE s.doctor_id = '550e8400-e29b-41d4-a716-446655440004'
AND s.work_date = '2024-12-15'
AND a.status = 'scheduled'
ORDER BY a.appointment_time;
```
Sort (cost=731.51..731.52 rows=1 width=32) (actual time=0.087..0.090 rows=0 loops=1)
" Output: a.appointment_id, p.name, a.appointment_time"
Sort Key: a.appointment_time
Sort Method: quicksort Memory: 25kB
-> Nested Loop (cost=8.60..731.50 rows=1 width=32) (actual time=0.053..0.055 rows=0 loops=1)
" Output: a.appointment_id, p.name, a.appointment_time"
Inner Unique: true
-> Hash Join (cost=8.32..731.09 rows=1 width=40) (actual time=0.052..0.054 rows=0 loops=1)
" Output: a.appointment_id, a.appointment_time, a.patient_id"
Inner Unique: true
Hash Cond: (a.schedule_id = s.schedule_id)
-> Seq Scan on hms.appointment a (cost=0.00..696.50 rows=10008 width=56) (actual time=0.028..0.028 rows=1 loops=1)
" Output: a.appointment_id, a.patient_id, a.schedule_id, a.appointment_time, a.status, a.booking_channel, a.created_at, a.cancelled_at, a.cancel_reason"
Filter: ((a.status)::text = 'scheduled'::text)
Rows Removed by Filter: 4
-> Hash (cost=8.31..8.31 rows=1 width=16) (actual time=0.014..0.015 rows=0 loops=1)
Output: s.schedule_id
Buckets: 1024 Batches: 1 Memory Usage: 8kB
-> Index Scan using schedule_doctor_id_work_date_slot_no_key on hms.schedule s (cost=0.29..8.31 rows=1 width=16) (actual time=0.014..0.014 rows=0 loops=1)
Output: s.schedule_id
Index Cond: ((s.doctor_id = '550e8400-e29b-41d4-a716-446655440004'::uuid) AND (s.work_date = '2024-12-15'::date))
-> Index Scan using patient_pkey on hms.patient p (cost=0.29..0.41 rows=1 width=24) (never executed)
" Output: p.patient_id, p.name, p.id_number, p.mobile, p.email, p.gender, p.birth_date, p.address, p.status, p.created_at, p.updated_at"
Index Cond: (p.patient_id = a.patient_id)
Planning Time: 1.273 ms
Execution Time: 0.119 ms
```sql
-- ============================================
-- 功能05更新预约状态为"已签到"
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE appointment SET status = 'checked_in'
WHERE appointment_id = '550e8400-e29b-41d4-a716-446655440005';
```
Update on hms.appointment (cost=0.29..8.30 rows=0 width=0) (actual time=0.016..0.016 rows=0 loops=1)
-> Index Scan using appointment_pkey on hms.appointment (cost=0.29..8.30 rows=1 width=64) (actual time=0.015..0.015 rows=0 loops=1)
" Output: 'checked_in'::character varying(20), ctid"
Index Cond: (appointment.appointment_id = '550e8400-e29b-41d4-a716-446655440005'::uuid)
Planning Time: 0.079 ms
Execution Time: 0.061 ms
```sql
-- ============================================
-- 功能06创建初始病历记录
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
INSERT INTO medical_record (record_id, patient_id, doctor_id, appointment_id, visit_time)
VALUES (gen_random_uuid(), '5e8d512a-22c9-4272-9cc7-b5b602b447c6',
'51e660c9-8270-439b-b33a-12230b5f27b2',
'3221a9b3-05e2-4375-92ce-f395ca05115f',
CURRENT_TIMESTAMP);
```
Insert on hms.medical_record (cost=0.00..0.03 rows=0 width=0) (actual time=0.068..0.069 rows=0 loops=1)
-> Result (cost=0.00..0.03 rows=1 width=1312) (actual time=0.024..0.024 rows=1 loops=1)
" Output: gen_random_uuid(), '5e8d512a-22c9-4272-9cc7-b5b602b447c6'::uuid, '51e660c9-8270-439b-b33a-12230b5f27b2'::uuid, '3221a9b3-05e2-4375-92ce-f395ca05115f'::uuid, CURRENT_TIMESTAMP, NULL::text, NULL::text, NULL::text, NULL::character varying(255), NULL::character varying(255), NULL::text, NULL::text, NULL::text, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP"
Planning Time: 0.023 ms
Trigger RI_ConstraintTrigger_c_27594 for constraint fk_record_patient: time=0.112 calls=1
Trigger RI_ConstraintTrigger_c_27599 for constraint fk_record_doctor: time=0.056 calls=1
Trigger RI_ConstraintTrigger_c_27604 for constraint fk_record_appointment: time=0.558 calls=1
Execution Time: 0.813 ms
```sql
-- ============================================
-- 功能07更新病历诊断信息
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE medical_record
SET chief_complaint = '头痛、发热3天',
diagnosis_codes = '上呼吸道感染,高血压',
updated_at = CURRENT_TIMESTAMP
WHERE record_id = '550e8400-e29b-41d4-a716-446655440009';
```
Update on hms.medical_record (cost=0.29..8.31 rows=0 width=0) (actual time=0.022..0.022 rows=0 loops=1)
-> Index Scan using medical_record_pkey on hms.medical_record (cost=0.29..8.31 rows=1 width=562) (actual time=0.020..0.020 rows=0 loops=1)
" Output: '头痛、发热3天'::text, '上呼吸道感染,高血压'::character varying(255), CURRENT_TIMESTAMP, ctid"
Index Cond: (medical_record.record_id = '550e8400-e29b-41d4-a716-446655440009'::uuid)
Planning Time: 0.064 ms
Execution Time: 0.056 ms
```sql
-- ============================================
-- 功能08创建处方主记录
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
INSERT INTO prescription (prescription_id, record_id, doctor_id, status)
VALUES ('5fcd0fcb-e522-43fb-b82e-8270c70aeb03', '05e5fe94-6b58-4e08-ae06-fc6990793c29',
'0193cd15-f4c4-4331-beaa-01fb67a3d00c', 'pending');
```
Insert on hms.prescription (cost=0.00..0.01 rows=0 width=0) (actual time=1.102..1.102 rows=0 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=138) (actual time=0.002..0.003 rows=1 loops=1)
" Output: '5fcd0fcb-e522-43fb-b82e-8270c70aeb03'::uuid, '05e5fe94-6b58-4e08-ae06-fc6990793c29'::uuid, '0193cd15-f4c4-4331-beaa-01fb67a3d00c'::uuid, CURRENT_TIMESTAMP, 'pending'::character varying(20), NULL::uuid, NULL::timestamp without time zone"
Planning Time: 0.020 ms
Trigger RI_ConstraintTrigger_c_27620 for constraint fk_prescription_record: time=0.083 calls=1
Trigger RI_ConstraintTrigger_c_27625 for constraint fk_prescription_doctor: time=0.094 calls=1
Execution Time: 1.288 ms
```sql
-- ============================================
-- 功能09添加处方明细项
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
INSERT INTO prescription_item (item_id, prescription_id, drug_id, dosage, frequency, duration_days, quantity)
VALUES (gen_random_uuid(), '550e8400-e29b-51d4-a716-446655440012',
'550e8400-e29b-41d4-a716-446655440013',
'1片', '每日3次', 7, 21);
```
Insert on hms.prescription_item (cost=0.00..0.01 rows=0 width=0) (actual time=0.087..0.088 rows=0 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=356) (actual time=0.019..0.019 rows=1 loops=1)
" Output: gen_random_uuid(), '550e8400-e29b-51d4-a716-446655440012'::uuid, '550e8400-e29b-41d4-a716-446655440013'::uuid, '1片'::character varying(50), '每日3次'::character varying(50), 7, 21, NULL::text, NULL::numeric(10,2), NULL::numeric(10,2)"
Planning Time: 0.025 ms
Execution Time: 0.102 ms
```sql
-- ============================================
-- 功能10查询处方明细清单
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT d.generic_name, i.dosage, i.frequency, i.quantity
FROM prescription_item i
JOIN drug d ON i.drug_id = d.drug_id
WHERE i.prescription_id = '550e8400-e29b-41d4-a716-446655440014';
```
Nested Loop (cost=4.71..40.80 rows=3 width=30) (actual time=0.358..0.358 rows=0 loops=1)
" Output: d.generic_name, i.dosage, i.frequency, i.quantity"
Inner Unique: true
-> Bitmap Heap Scan on hms.prescription_item i (cost=4.44..15.91 rows=3 width=37) (actual time=0.357..0.357 rows=0 loops=1)
" Output: i.item_id, i.prescription_id, i.drug_id, i.dosage, i.frequency, i.duration_days, i.quantity, i.instructions, i.price, i.amount"
Recheck Cond: (i.prescription_id = '550e8400-e29b-41d4-a716-446655440014'::uuid)
-> Bitmap Index Scan on prescription_item_prescription_id_drug_id_key (cost=0.00..4.44 rows=3 width=0) (actual time=0.339..0.339 rows=0 loops=1)
Index Cond: (i.prescription_id = '550e8400-e29b-41d4-a716-446655440014'::uuid)
-> Index Scan using drug_pkey on hms.drug d (cost=0.28..8.29 rows=1 width=25) (never executed)
" Output: d.drug_id, d.generic_name, d.trade_name, d.specification, d.unit, d.dosage_form, d.manufacturer, d.approval_no, d.is_prescription, d.shelf_life_days, d.storage_conditions, d.created_at"
Index Cond: (d.drug_id = i.drug_id)
Planning Time: 0.342 ms
Execution Time: 0.376 ms
```sql
-- ============================================
-- 功能11更新处方审核状态
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE prescription SET status = 'approved',
pharmacist_id = '550e8400-e29b-41d4-a716-446655440015',
reviewed_at = CURRENT_TIMESTAMP
WHERE prescription_id = '550e8400-e29b-41d4-a716-446655440016';
```
Update on hms.prescription (cost=0.29..8.31 rows=0 width=0) (actual time=0.015..0.015 rows=0 loops=1)
-> Index Scan using prescription_pkey on hms.prescription (cost=0.29..8.31 rows=1 width=88) (actual time=0.014..0.014 rows=0 loops=1)
" Output: 'approved'::character varying(20), '550e8400-e29b-41d4-a716-446655440015'::uuid, CURRENT_TIMESTAMP, ctid"
Index Cond: (prescription.prescription_id = '550e8400-e29b-41d4-a716-446655440016'::uuid)
Planning Time: 0.075 ms
Execution Time: 0.042 ms
```sql
-- ============================================
-- 功能12查询药品库存可用数量
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT SUM(current_stock) AS total_stock
FROM inventory_batch
WHERE drug_id = '550e8400-e29b-41d4-a716-446655440017';
```
Aggregate (cost=149.51..149.52 rows=1 width=8) (actual time=0.500..0.500 rows=1 loops=1)
Output: sum(current_stock)
-> Seq Scan on hms.inventory_batch (cost=0.00..149.50 rows=5 width=4) (actual time=0.494..0.494 rows=0 loops=1)
" Output: batch_id, drug_id, batch_no, production_date, expiry_date, purchase_quantity, purchase_price, purchase_date, current_stock, department_id, min_stock_threshold, last_stock_in, last_stock_out"
Filter: (inventory_batch.drug_id = '550e8400-e29b-41d4-a716-446655440017'::uuid)
Rows Removed by Filter: 5000
Planning Time: 0.131 ms
Execution Time: 0.515 ms
```sql
-- ============================================
-- 功能13扣减药品库存
-- ============================================
-- 查询符合条件的批次(用于查看执行计划)
EXPLAIN (ANALYZE, VERBOSE)
SELECT batch_id FROM inventory_batch
WHERE drug_id = '550e8400-e29b-41d4-a716-446655440018'
AND current_stock >= 10
ORDER BY expiry_date ASC LIMIT 1;
```
Limit (cost=162.03..162.03 rows=1 width=20) (actual time=0.537..0.538 rows=0 loops=1)
" Output: batch_id, expiry_date"
-> Sort (cost=162.03..162.04 rows=5 width=20) (actual time=0.536..0.536 rows=0 loops=1)
" Output: batch_id, expiry_date"
Sort Key: inventory_batch.expiry_date
Sort Method: quicksort Memory: 25kB
-> Seq Scan on hms.inventory_batch (cost=0.00..162.00 rows=5 width=20) (actual time=0.525..0.525 rows=0 loops=1)
" Output: batch_id, expiry_date"
Filter: ((inventory_batch.current_stock >= 10) AND (inventory_batch.drug_id = '550e8400-e29b-41d4-a716-446655440018'::uuid))
Rows Removed by Filter: 5000
Planning Time: 0.127 ms
Execution Time: 0.550 ms
```sql
-- ============================================
-- 功能14更新处方状态为"已发药"
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
UPDATE prescription SET status = 'dispensed'
WHERE prescription_id = '550e8400-e29b-41d4-a716-446655440020';
```
Update on hms.prescription (cost=0.29..8.30 rows=0 width=0) (actual time=0.015..0.015 rows=0 loops=1)
-> Index Scan using prescription_pkey on hms.prescription (cost=0.29..8.30 rows=1 width=64) (actual time=0.014..0.014 rows=0 loops=1)
" Output: 'dispensed'::character varying(20), ctid"
Index Cond: (prescription.prescription_id = '550e8400-e29b-41d4-a716-446655440020'::uuid)
Planning Time: 0.080 ms
Execution Time: 0.031 ms
```sql
-- ============================================
-- 功能15取消预约并回退号源
-- ============================================
-- 更新预约状态
EXPLAIN (ANALYZE, VERBOSE)
UPDATE appointment SET status = 'cancelled', cancelled_at = CURRENT_TIMESTAMP
WHERE appointment_id = '550e8400-e29b-41d4-a716-446655440021';
```
Update on hms.appointment (cost=0.29..8.31 rows=0 width=0) (actual time=0.014..0.014 rows=0 loops=1)
-> Index Scan using appointment_pkey on hms.appointment (cost=0.29..8.31 rows=1 width=72) (actual time=0.013..0.013 rows=0 loops=1)
" Output: 'cancelled'::character varying(20), CURRENT_TIMESTAMP, ctid"
Index Cond: (appointment.appointment_id = '550e8400-e29b-41d4-a716-446655440021'::uuid)
Planning Time: 0.062 ms
Execution Time: 0.029 ms
```sql
-- 回退号源(子查询版本)
EXPLAIN (ANALYZE, VERBOSE)
UPDATE schedule SET remaining_appointments = remaining_appointments + 1
WHERE schedule_id = (SELECT schedule_id FROM appointment
WHERE appointment_id = '550e8400-e29b-41d4-a716-446655440022');
```
Update on hms.schedule (cost=8.59..16.61 rows=0 width=0) (actual time=0.019..0.019 rows=0 loops=1)
InitPlan 1
-> Index Scan using appointment_pkey on hms.appointment (cost=0.29..8.30 rows=1 width=16) (actual time=0.007..0.007 rows=0 loops=1)
Output: appointment.schedule_id
Index Cond: (appointment.appointment_id = '550e8400-e29b-41d4-a716-446655440022'::uuid)
-> Index Scan using schedule_pkey on hms.schedule (cost=0.29..8.31 rows=1 width=10) (actual time=0.018..0.018 rows=0 loops=1)
" Output: (schedule.remaining_appointments + 1), schedule.ctid"
Index Cond: (schedule.schedule_id = (InitPlan 1).col1)
Planning Time: 0.101 ms
Execution Time: 0.038 ms
```sql
-- ============================================
-- 功能16查询库存预警药品
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT d.generic_name, SUM(ib.current_stock) AS total_stock
FROM drug d
JOIN inventory_batch ib ON d.drug_id = ib.drug_id
GROUP BY d.drug_id, d.generic_name, ib.min_stock_threshold
HAVING SUM(ib.current_stock) < ib.min_stock_threshold;
```
HashAggregate (cost=234.18..284.18 rows=1333 width=37) (actual time=1.724..1.869 rows=14 loops=1)
" Output: d.generic_name, sum(ib.current_stock), d.drug_id, ib.min_stock_threshold"
" Group Key: d.drug_id, ib.min_stock_threshold"
Filter: (sum(ib.current_stock) < ib.min_stock_threshold)
Batches: 1 Memory Usage: 721kB
Rows Removed by Filter: 2896
-> Hash Join (cost=46.50..196.68 rows=5000 width=33) (actual time=0.197..1.071 rows=5000 loops=1)
" Output: d.drug_id, ib.min_stock_threshold, d.generic_name, ib.current_stock"
Inner Unique: true
Hash Cond: (ib.drug_id = d.drug_id)
-> Seq Scan on hms.inventory_batch ib (cost=0.00..137.00 rows=5000 width=24) (actual time=0.006..0.167 rows=5000 loops=1)
" Output: ib.batch_id, ib.drug_id, ib.batch_no, ib.production_date, ib.expiry_date, ib.purchase_quantity, ib.purchase_price, ib.purchase_date, ib.current_stock, ib.department_id, ib.min_stock_threshold, ib.last_stock_in, ib.last_stock_out"
-> Hash (cost=34.00..34.00 rows=1000 width=25) (actual time=0.185..0.185 rows=1000 loops=1)
" Output: d.generic_name, d.drug_id"
Buckets: 1024 Batches: 1 Memory Usage: 65kB
-> Seq Scan on hms.drug d (cost=0.00..34.00 rows=1000 width=25) (actual time=0.006..0.113 rows=1000 loops=1)
" Output: d.generic_name, d.drug_id"
Planning Time: 0.155 ms
Execution Time: 1.989 ms
```sql
-- ============================================
-- 功能17统计科室预约量
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT dep.name, COUNT(a.appointment_id) as appointment_count
FROM department dep
JOIN doctor d ON dep.department_id = d.department_id
JOIN schedule s ON d.doctor_id = s.doctor_id
LEFT JOIN appointment a ON s.schedule_id = a.schedule_id
WHERE s.work_date = '2024-12-15'
GROUP BY dep.department_id, dep.name;
```
GroupAggregate (cost=1379.43..1379.45 rows=1 width=242) (actual time=2.454..2.459 rows=0 loops=1)
" Output: dep.name, count(a.appointment_id), dep.department_id"
Group Key: dep.department_id
-> Sort (cost=1379.43..1379.44 rows=1 width=250) (actual time=2.453..2.457 rows=0 loops=1)
" Output: dep.department_id, dep.name, a.appointment_id"
Sort Key: dep.department_id
Sort Method: quicksort Memory: 25kB
-> Nested Loop (cost=671.72..1379.42 rows=1 width=250) (actual time=2.436..2.440 rows=0 loops=1)
" Output: dep.department_id, dep.name, a.appointment_id"
Inner Unique: true
-> Nested Loop (cost=671.58..1379.24 rows=1 width=32) (actual time=2.436..2.439 rows=0 loops=1)
" Output: d.department_id, a.appointment_id"
Inner Unique: true
-> Hash Right Join (cost=671.30..1370.94 rows=1 width=32) (actual time=2.435..2.438 rows=0 loops=1)
" Output: s.doctor_id, a.appointment_id"
Inner Unique: true
Hash Cond: (a.schedule_id = s.schedule_id)
-> Seq Scan on hms.appointment a (cost=0.00..634.00 rows=25000 width=32) (never executed)
" Output: a.appointment_id, a.patient_id, a.schedule_id, a.appointment_time, a.status, a.booking_channel, a.created_at, a.cancelled_at, a.cancel_reason"
-> Hash (cost=671.29..671.29 rows=1 width=32) (actual time=2.428..2.430 rows=0 loops=1)
" Output: s.doctor_id, s.schedule_id"
Buckets: 1024 Batches: 1 Memory Usage: 8kB
-> Seq Scan on hms.schedule s (cost=0.00..671.29 rows=1 width=32) (actual time=2.427..2.427 rows=0 loops=1)
" Output: s.doctor_id, s.schedule_id"
Filter: (s.work_date = '2024-12-15'::date)
Rows Removed by Filter: 27703
-> Index Scan using doctor_pkey on hms.doctor d (cost=0.28..8.29 rows=1 width=32) (never executed)
" Output: d.doctor_id, d.department_id, d.name, d.title, d.license_no, d.contact, d.work_status"
Index Cond: (d.doctor_id = s.doctor_id)
-> Index Scan using department_pkey on hms.department dep (cost=0.14..0.18 rows=1 width=234) (never executed)
" Output: dep.department_id, dep.code, dep.name, dep.location, dep.phone"
Index Cond: (dep.department_id = d.department_id)
Planning Time: 0.311 ms
Execution Time: 2.495 ms
```sql
-- ============================================
-- 功能18统计医生工作量
-- ============================================
EXPLAIN (ANALYZE, VERBOSE)
SELECT d.name, COUNT(mr.record_id) as record_count
FROM doctor d
LEFT JOIN medical_record mr ON d.doctor_id = mr.doctor_id
AND EXTRACT(YEAR FROM mr.visit_time) = 2024
AND EXTRACT(MONTH FROM mr.visit_time) = 12
WHERE d.work_status = 'active'
GROUP BY d.doctor_id, d.name;
```
GroupAggregate (cost=5247.03..5270.93 rows=1194 width=32) (actual time=13.444..14.002 rows=1194 loops=1)
" Output: d.name, count(mr.record_id), d.doctor_id"
Group Key: d.doctor_id
-> Merge Left Join (cost=5247.03..5253.02 rows=1194 width=40) (actual time=13.439..13.643 rows=1295 loops=1)
" Output: d.doctor_id, d.name, mr.record_id"
Merge Cond: (d.doctor_id = mr.doctor_id)
-> Sort (cost=114.02..117.01 rows=1194 width=24) (actual time=0.345..0.384 rows=1194 loops=1)
" Output: d.name, d.doctor_id"
Sort Key: d.doctor_id
Sort Method: quicksort Memory: 98kB
-> Seq Scan on hms.doctor d (cost=0.00..53.00 rows=1194 width=24) (actual time=0.006..0.200 rows=1194 loops=1)
" Output: d.name, d.doctor_id"
Filter: ((d.work_status)::text = 'active'::text)
Rows Removed by Filter: 806
-> Sort (cost=5133.01..5133.02 rows=1 width=32) (actual time=13.090..13.111 rows=865 loops=1)
" Output: mr.record_id, mr.doctor_id"
Sort Key: mr.doctor_id
Sort Method: quicksort Memory: 65kB
-> Seq Scan on hms.medical_record mr (cost=0.00..5133.00 rows=1 width=32) (actual time=0.016..12.946 rows=865 loops=1)
" Output: mr.record_id, mr.doctor_id"
Filter: ((EXTRACT(year FROM mr.visit_time) = '2024'::numeric) AND (EXTRACT(month FROM mr.visit_time) = '12'::numeric))
Rows Removed by Filter: 19136
Planning Time: 0.171 ms
Execution Time: 14.051 ms
```sql
-- 1. 各表数据量统计
SELECT 'department' as table_name, COUNT(*) as row_count FROM department
UNION ALL
SELECT 'doctor', COUNT(*) FROM doctor
UNION ALL
SELECT 'patient', COUNT(*) FROM patient
UNION ALL
SELECT 'drug', COUNT(*) FROM drug
UNION ALL
SELECT 'inventory_batch', COUNT(*) FROM inventory_batch
UNION ALL
SELECT 'schedule', COUNT(*) FROM schedule
UNION ALL
SELECT 'appointment', COUNT(*) FROM appointment
UNION ALL
SELECT 'medical_record', COUNT(*) FROM medical_record
UNION ALL
SELECT 'prescription', COUNT(*) FROM prescription
UNION ALL
SELECT 'prescription_item', COUNT(*) FROM prescription_item;
```
prescription_item,45002
medical_record,20001
appointment,25001
schedule,27703
prescription,18001
patient,10000
inventory_batch,5000
doctor,2000
drug,1000
department,50
```sql
-- 2. 现有索引检查(使用系统表)
SELECT
t.relname as table_name,
i.relname as index_name,
a.attname as column_name
FROM pg_class t
JOIN pg_index ix ON t.oid = ix.indrelid
JOIN pg_class i ON i.oid = ix.indexrelid
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey)
WHERE t.relkind = 'r'
AND t.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public')
ORDER BY t.relname, i.relname;
```
# 完整运行结果
| | | | | | | | | |
|---|---|---|---|---|---|---|---|---|
|SELECT (select)||||||||Planning Time = 0.375; Triggers = []; Execution Time = 0.1;|
|SORT (sort)||3|0|49.36|0.073|49.35|0.072|Parallel Aware = false; Async Capable = false; Plan Width = 192; Actual Loops = 1; Sort Key = ["t.relname","i.relname"]; Sort Method = quicksort; Sort Space Used = 25; Sort Space Type = Memory;|
|SEQ_SCAN (Seq Scan)|table: pg_namespace;|1|0|1.05|0.004|0.0|0.004|Parent Relationship = InitPlan; Subplan Name = InitPlan 1; Parallel Aware = false; Async Capable = false; Alias = pg_namespace; Plan Width = 4; Actual Loops = 1; Filter = (nspname = 'public'::name); Rows Removed by Filter = 7;|
|NESTED_LOOPS (Nested Loop)||3|0|48.28|0.067|21.54|0.067|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Inner; Plan Width = 192; Actual Loops = 1; Inner Unique = true;|
|NESTED_LOOPS (Nested Loop)||3|0|46.09|0.067|21.27|0.066|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Inner; Plan Width = 132; Actual Loops = 1; Inner Unique = false; Join Filter = (t.oid = a.attrelid); Rows Removed by Join Filter = 0;|
|HASH_JOIN (hash join)||7|0|28.06|0.067|20.99|0.066|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Join Type = Inner; Plan Width = 103; Actual Loops = 1; Inner Unique = true; Hash Cond = (ix.indrelid = t.oid);|
|SEQ_SCAN (Seq Scan)|table: pg_index;|164|1|6.64|0.007|0.0|0.007|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = ix; Plan Width = 35; Actual Loops = 1;|
|TRANSFORM (Hash)||19|0|20.75|0.054|20.75|0.054|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Plan Width = 68; Actual Loops = 1; Hash Buckets = 1024; Original Hash Buckets = 1024; Hash Batches = 1; Original Hash Batches = 1; Peak Memory Usage = 8;|
|SEQ_SCAN (Seq Scan)|table: pg_class;|19|0|20.75|0.054|0.0|0.054|Parent Relationship = Outer; Parallel Aware = false; Async Capable = false; Alias = t; Plan Width = 68; Actual Loops = 1; Filter = ((relkind = 'r'::"char") AND (relnamespace = (InitPlan 1).col1)); Rows Removed by Filter = 454;|
|INDEX_SCAN (index scan)|table: pg_attribute; index: pg_attribute_relid_attnam_index;|1|0|2.56|0.0|0.28|0.0|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Scan Direction = Forward; Alias = a; Plan Width = 70; Actual Loops = 0; Index Cond = (attrelid = ix.indrelid); Rows Removed by Index Recheck = 0; Filter = (attnum = ANY ((ix.indkey)::smallint[])); Rows Removed by Filter = 0;|
|INDEX_SCAN (index scan)|table: pg_class; index: pg_class_oid_index;|1|0|0.73|0.0|0.27|0.0|Parent Relationship = Inner; Parallel Aware = false; Async Capable = false; Scan Direction = Forward; Alias = i; Plan Width = 68; Actual Loops = 0; Index Cond = (oid = ix.indexrelid); Rows Removed by Index Recheck = 0;|
Loading…
Cancel
Save