Jason's answer is in place. In addition, I will try to use the more advanced ANSI join syntax to unload the WHERE clause in order to eliminate confusion:
SELECT o.id FROM programs o JOIN titles_programs t ON t.object_id=o.id JOIN descriptions_programs d ON d.object_id=o.id WHERE MATCH (d.text) AGAINST ('+china' IN BOOLEAN MODE) AND d.current=1 OR MATCH (t.text) AGAINST ('+china' IN BOOLEAN MODE) AND t.current=1
This will stop the unintended cross-connection causing a combinatorial explosion; I expect it to work in a reasonable amount of time if the database is not really huge.
If not, can you post the EXPLAIN SELECT results from the above? Presumably, one or both of the full-text indexes are not used. I could, of course, assume that the query optimizer will not be able to use the second full-text index, making something like an attempt to "populate lines that do not match the first full-text query, and not go directly to the index or something like that.
Usually, if you want to use a full-text index on two columns in combination, you create one index on both columns. In any case, it will be much faster. However, this would mean that you should include the names and descriptions in the same table. This may not be so difficult: since fulltext only works with MyISAM tables (and usually you donβt need your canonical data in MyISAM tables), you can save the final copy of your data in normalized InnoDB tables with an additional MyISAM table containing only undressed and buttoned search bait .
If none of this works ... well, I think I will go back to the UNIONing that you talked about in combination with an application-level filter to remove duplicate identifiers.
source share