terrymanu commented on issue #35245:
URL:
https://github.com/apache/shardingsphere/issues/35245#issuecomment-3491784051
Problem Analysis
Thank you for reporting this issue. After thorough analysis of
ShardingSphere's code implementation, I have identified the root cause of this
problem.
You are experiencing an issue where: customer is configured as a Single
Table, order_item as a Sharding Table, and creating a foreign key constraint
results in a "Table 'customer' already exists" error.
Root Cause
The root cause of this issue is ShardingSphere's architectural limitation
when handling foreign key constraints between Single Tables and Sharding
Tables, not a simple table existence check problem.
Technical Analysis
1. Single Table Characteristics: The customer table is configured as a
Single Table, stored only in one specified data source
2. Sharding Table Characteristics: The order_item table is a Sharding
Table, distributed across multiple data sources according to sharding strategy
3. Foreign Key Constraint Processing: When creating a foreign key on a
sharding table, ShardingSphere's constraint processor
(ShardingConstraintReviser) attempts to rewrite the foreign key constraint to
adapt to the
sharding environment
Key Code Path
The issue occurs in the following code path:
// ShardingConstraintReviser.java:40-48
for (DataNode each : shardingTable.getActualDataNodes()) {
String referencedTableName = originalMetaData.getReferencedTableName();
Optional<String> logicIndexName =
getLogicIndex(originalMetaData.getName(), each.getTableName());
if (logicIndexName.isPresent()) {
return Optional.of(new ConstraintMetaData(
logicIndexName.get(),
rule.getAttributes().getAttribute(DataNodeRuleAttribute.class).findLogicTableByActualTable(referencedTableName).orElse(referencedTableName)));
}
}
When the constraint processor iterates through all data nodes of the
sharding table, it cannot properly handle references to Single Tables, leading
to table existence conflicts during foreign key constraint processing.
ShardingSphere Architectural Limitations
Why Cross-Type Table Foreign Key Constraints Are Not Supported
1. Data Integrity Guarantee Difficulty: In distributed environments,
maintaining data consistency between Single Tables and Sharding Tables is
extremely costly
2. Routing Complexity: Single Tables use direct routing, Sharding Tables
use sharding routing, and cross-type foreign key constraints require unified
routing processing mechanisms
3. Performance Impact: Cross-datasource foreign key constraint checks
severely impact query and write performance
4. Transaction Complexity: Foreign key constraints require
cross-datasource distributed transaction support
ShardingSphere Design Principles
Code analysis shows that ShardingSphere primarily considers operations
between tables of the same type when designed:
- SingleConstraintReviser: Handles constraints within Single Tables
- ShardingConstraintReviser: Handles constraints between Sharding Tables
- Lacks dedicated processors for handling foreign key constraints between
Single Tables and Sharding Tables
Solutions
Solution 1: Unify Table Types (Recommended)
Configure both customer and order_item as Sharding Tables with the same or
compatible sharding strategies:
ShardingRuleConfiguration shardingRuleConfig = new
ShardingRuleConfiguration();
// Configure customer table as single-shard table (not sharded but managed
as Sharding Table)
ShardingTableRuleConfiguration customerTable = new
ShardingTableRuleConfiguration(
"customer", "ds.customer");
shardingRuleConfig.getTables().add(customerTable);
// order_item table with normal sharding
ShardingTableRuleConfiguration orderItemTable = new
ShardingTableRuleConfiguration(
"order_item", "ds.order_item_${order_id % 4}");
shardingRuleConfig.getTables().add(orderItemTable);
// Configure sharding strategy
shardingRuleConfig.getShardingAlgorithms().put(
"order_item_sharding", new
StandardShardingStrategyConfiguration("order_id", "order_item_mod"));
Solution 2: Implement Foreign Key Logic at Business Layer
Implement foreign key constraint checks at the application layer:
@Service
public class OrderItemService {
@Autowired
private CustomerRepository customerRepository;
@Autowired
private OrderItemRepository orderItemRepository;
@Transactional
public void createOrderItem(OrderItem orderItem) {
// Business layer foreign key check
if (!customerRepository.existsById(orderItem.getCustomerId())) {
throw new BusinessException("Customer not found: " +
orderItem.getCustomerId());
}
orderItemRepository.save(orderItem);
}
}
Solution 3: Use Sharding Table Reference Rules
If forced association is needed, use ShardingSphere's binding table
configuration:
ShardingTableReferenceRuleConfiguration referenceRule =
new ShardingTableReferenceRuleConfiguration(
"customer_order_item",
"customer",
"order_item"
);
shardingRuleConfig.getBindingTableGroups().add(referenceRule);
Temporary Solutions
If you must maintain the current table structure configuration, the
following temporary solutions can be used:
Use IF NOT EXISTS Syntax
-- Use IF NOT EXISTS when creating order_item table
CREATE TABLE IF NOT EXISTS order_item (
id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
FOREIGN KEY (customer_id) REFERENCES customer(id)
);
Create Foreign Key Constraint Separately
-- Create in steps
-- 1. First create table (without foreign key)
CREATE TABLE order_item (
id INT PRIMARY KEY,
customer_id INT,
order_date DATE
);
-- 2. Then add foreign key constraint separately
ALTER TABLE order_item ADD CONSTRAINT fk_order_item_customer
FOREIGN KEY (customer_id) REFERENCES customer(id);
Best Practice Recommendations
1. Avoid Cross-Type Table Foreign Key Constraints: This is an
architectural limitation of ShardingSphere, not officially recommended
2. Unify Table Types: For tables requiring foreign key associations, it's
recommended to configure them as the same type (both as Sharding Tables or both
as Single Tables)
3. Business Layer Implementation: Implement foreign key logic at the
application layer, using transactions to ensure data consistency
4. Regular Data Validation: Perform data integrity validation through
scheduled tasks
Summary
This issue reflects ShardingSphere's architectural limitations when
handling mixed table type scenarios. Although temporary solutions can bypass
the error, in the long term, it's recommended to redesign table structure to
use unified table types or implement foreign key logic at the application
layer.
This issue has been widely discussed in the ShardingSphere community, and
the official stance is not to recommend creating foreign key constraints
between Single Tables and Sharding Tables, as this pattern presents
fundamental technical challenges in distributed environments.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]