Hi there, I am a bit new to all of this and have had my first run in with a deadlock situation.
We know what is causing the deadlock but are unsure what the best solution is to fix the problem.
In our simplest case we have the following tables with three common transactions on them.
AssetMetaData: metadata_id (pk), name, asset_id, version_id
AssetDependencies: metadata_id, dependency_asset_id (many entries per metadata id)
Our database is structured in such a way that we have unique "assets" of which all can have multiple versions of the asset. Each time someone edits an asset a new set of table data is provided for the user to work with (so a new metadata entry with the same asset id but a new version id) These two combined are represented in other tables in the form of our auto incrementing metadata id.
Our common transactions that have deadlock issues are:
Save -
Update Metadata row with our metadata_id
Clear current associated dependencies with our metadata_id
Insert new dependencies with our metadata_id
Revert -
Delete all dependency rows with our metadata_id
Delete metadata row with our metadata_id
Checkout -
Find the current version of the asset in metadata table, insert new row as a copy but with a new auto increment metadata_id
Find all dependencies with the old id and insert them into the table with the new id (insert into from select)
Our common problem is that for foreign key/creation problems and also the fact multiple people are writing the code that our table are referenced in different orders. So one user will lock metadata and try to lock dependencies while the other user has a lock on dependencies and wants metadata.
Re-ordering is possible for the cases that do not create the metadata row, but in the creation cases it needs to go first where every deletion case it needs to go last due to foreign keys. I do not know how locks work in this regard though so I dont know if it is an issue. Re-ordering however seems fragile, someone else could come along and write his own save in a different order and things would appear ok until there is a high traffic day and then we would have problems again.
We know in these cases that no two users are editing the same rows so we were hoping only row locks would be used and no collisions would occur. Of course the database could always decide to promote to a table lock on us especially in cases like the dependencies table if there are enough dependencies being changed. Also in a case where we "UPDATE metadata WHERE metadata_id = @metadata_id" the sproc seems to get a U lock while looking for the row and ends up with a X lock on the specific row. But the U lock gets stuck if someone else has a specific row lock before we could lock our specific but different row.
Our current thinking is that we just need to forward declare our locks in the same order which would be easier to enforce, but my attempts at that seem to either be wrong or incorrect in our approach.
What do people suggest we do?
Is there any other information I can provide?
Thanks,
DClyde
We know what is causing the deadlock but are unsure what the best solution is to fix the problem.
In our simplest case we have the following tables with three common transactions on them.
AssetMetaData: metadata_id (pk), name, asset_id, version_id
AssetDependencies: metadata_id, dependency_asset_id (many entries per metadata id)
Our database is structured in such a way that we have unique "assets" of which all can have multiple versions of the asset. Each time someone edits an asset a new set of table data is provided for the user to work with (so a new metadata entry with the same asset id but a new version id) These two combined are represented in other tables in the form of our auto incrementing metadata id.
Our common transactions that have deadlock issues are:
Save -
Update Metadata row with our metadata_id
Clear current associated dependencies with our metadata_id
Insert new dependencies with our metadata_id
Revert -
Delete all dependency rows with our metadata_id
Delete metadata row with our metadata_id
Checkout -
Find the current version of the asset in metadata table, insert new row as a copy but with a new auto increment metadata_id
Find all dependencies with the old id and insert them into the table with the new id (insert into from select)
Our common problem is that for foreign key/creation problems and also the fact multiple people are writing the code that our table are referenced in different orders. So one user will lock metadata and try to lock dependencies while the other user has a lock on dependencies and wants metadata.
Re-ordering is possible for the cases that do not create the metadata row, but in the creation cases it needs to go first where every deletion case it needs to go last due to foreign keys. I do not know how locks work in this regard though so I dont know if it is an issue. Re-ordering however seems fragile, someone else could come along and write his own save in a different order and things would appear ok until there is a high traffic day and then we would have problems again.
We know in these cases that no two users are editing the same rows so we were hoping only row locks would be used and no collisions would occur. Of course the database could always decide to promote to a table lock on us especially in cases like the dependencies table if there are enough dependencies being changed. Also in a case where we "UPDATE metadata WHERE metadata_id = @metadata_id" the sproc seems to get a U lock while looking for the row and ends up with a X lock on the specific row. But the U lock gets stuck if someone else has a specific row lock before we could lock our specific but different row.
Our current thinking is that we just need to forward declare our locks in the same order which would be easier to enforce, but my attempts at that seem to either be wrong or incorrect in our approach.
What do people suggest we do?
Is there any other information I can provide?
Thanks,
DClyde