Q:

Multiple holes in object by boolean

I have a sphere with wall thickness that is separated for 3D print to 36 pieces that intersect a little. I need to randomly pierce it by holes. So I a made the 36 pieces a one object, model the cylinders also made them one object and then tried to subtract them from the sphere. As I expected, the Boolean went mad and it turned out badly. How to achieve the desired model with working Boolean or in other way? Here is my file.

A:

Answer A:
The reason it doesnt work is that you have a very bad (unecessarily huge and unstructered) topology (See 1). Using a fresh and nicely subdivided icosphere/uv-sphere the boolean operation should work better. (See 2) I'd also suggest to use simple topology cylinders with bevels instead of those highpoly triangled ones.
I'd say build it from scratch and lowpoly, but if you dont want to, to keep your creases/trenches you could also try the new remeshing options (Voxel/ Quadriflow) to get some clean topology.
Your specific modell is easily reproduced using a mirror-modifier workflow, after extracting the necessery parts from an UV-Sphere via Separate. (See 4, m-mod is not applied yet in image)

Answer B:
Workaround for unreliable boolean modifier when using a loose parts cutter objects - meaning the cutting objekt has multiple unconnected polygroups inside:
Separate your cutting object by loose parts and apply to every loose part to be cut a boolean modifier per loose part cutting object.(per cylinder in this case)
Doing this by hand is tedious! Here is a script to set boolean modifiers to the active object for every single object in a specified collection:
import bpy

#boolean modifier will be applyied to active object
obj_base = bpy.context.object
#per object in collection named "Coll_Cutter" the active objects gets one boolean modifier
collCutter_name = "Coll_Cutter"

for c in bpy.data.collections:
    print(c.name)
    if c.name == collCutter_name:
        cutterlist = c.all_objects

for cutter in cutterlist:
    bool_one = obj_base.modifiers.new(type="BOOLEAN", name="bool 1")
    bool_one.object = cutter
    bool_one.operation = 'DIFFERENCE'

