上篇記錄使用“CONCURRENTLY” 命令行執行不鎖表索引,對於django, 如何執行呢?這里記錄一種方法,修改django遷移文件。
在執行完遷移后,為了方便找到該遷移文件,可以采用指定命名遷移
python manage.py makemigrations --name=add_index_separate_database_and_state app01
對應app/migrations文件夾自動生成mitration文件,例如:
1 # migrations/0002_add_index_separate_database_and_state.py 2 3 from django.db import migrations, models 4 5 class Migration(migrations.Migration): 6 7 dependencies = [ 8 ('app', '0001_initial'), 9 ] 10 11 operations = [ 12 migrations.AlterField( 13 model_name='sale', 14 name='sold_at', 15 field=models.DateTimeField( 16 auto_now_add=True, 17 db_index=True, 18 ), 19 ), 20 ]
在終端輸出migratons文件sql語句,此處是為確保執行sql操作與django狀態一致
1 $ python manage.py sqlmigrate app 0002 2 BEGIN; 3 -- 4 -- Alter field sold_at on sale 5 -- 6 CREATE INDEX "app_sale_sold_at_b9438ae4" ON "app_sale" ("sold_at"); 7 COMMIT;
接下來,需要使用“SeparateDatabaseAndState”來進行關聯,我們知道,Django模型和數據庫屬於映射關系,django保存模型狀態,和數據庫之間同步需要明確指出。
1 # migrations/0002_add_index_separate_database_and_state.py 2 3 from django.db import migrations, models 4 5 class Migration(migrations.Migration): 6 atomic = False 7 8 dependencies = [ 9 ('app', '0001_initial'), 10 ] 11 12 operations = [ 13 14 migrations.SeparateDatabaseAndState( 15 16 state_operations=[ 17 migrations.AlterField( 18 model_name='sale', 19 name='sold_at', 20 field=models.DateTimeField( 21 auto_now_add=True, 22 db_index=True, 23 ), 24 ), 25 ], 26 27 database_operations=[ 28 migrations.RunSQL(sql=""" 29 CREATE INDEX CONCURRENTLY "app_sale_sold_at_b9438ae4" 30 ON "app_sale" ("sold_at"); 31 """, 32 reverse_sql=""" 33 DROP INDEX "app_sale_sold_at_b9438ae4"; 34 """), 35 ], 36 ), 37 38 ],
state_operations: django此次修改動作,django自動生成動作,
state_operations:數據庫執行操作,
reverse_sql: 類似與sql回滾,比如,遷移文件想回到上一版本時,需要將本遷移文件執行操作還原,但django不知道原始sql執行何種操作,所以,如果要回退,需要指定回滾sql。
另外,django遷移采用事務操作,而"CONCURRENTLY"不支持事務操作,可以采用非事務操作(不可回滾),如第6行所示。
文章參考:https://realpython.com/create-django-index-without-downtime/#execute-raw-sql-in-migrations