**Describe the solution you'd like**

We already can run clickhouse-server without configured ZooKeeper (the tables will start in read-only mode)
and with configured ZooKeeper, if it starts to be inaccessible at runtime (the tables will be read-only until the session is re-established).

Let's also make it possible to start up when ZooKeeper is unavailable.

**Additional context**

If that will be very hard to implement, we can consider other options:
- lazy attaching of the tables after sever start-up;
- a maintenance mode when the tables are not attached at start-up and require manual ATTACH queries.
}
    
    Strings parts_to_fetch;
    for (const String & missing_name : expected_parts)
        if (!getActiveContainingPart(missing_name))
            parts_to_fetch.push_back(missing_name);
    /** To check the adequacy, for the parts that are in the FS, but not in ZK, we will only consider not the most recent parts.
      * Because unexpected new parts usually arise only because they did not have time to enroll in ZK with a rough restart of the server.
      * It also occurs from deduplicated parts that did not have time to retire.
      */
    size_t unexpected_parts_nonnew = 0;
    UInt64 unexpected_parts_nonnew_rows = 0;
    UInt64 unexpected_parts_rows = 0;
    Strings covered_unexpected_parts;
    Strings uncovered_unexpected_parts;
    UInt64 uncovered_unexpected_parts_rows = 0;
    for (const auto & part : unexpected_parts)
    {
        unexpected_parts_rows += part->rows_count;
        
        
        String covering_local_part = local_expected_parts_set.getContainingPart(part->name);
        if (!covering_local_part.empty())
        {
            covered_unexpected_parts.push_back(part->name);
            continue;
        }
        
        uncovered_unexpected_parts.push_back(part->name);
        uncovered_unexpected_parts_rows += part->rows_count;